React中OTP输入框的事件处理与焦点管理如何实现

来源:AI编程作者:霓渡头衔:草根站长
导读:本期聚焦于小伙伴创作的《React中OTP输入框的事件处理与焦点管理如何实现》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《React中OTP输入框的事件处理与焦点管理如何实现》有用,将其分享出去将是对创作者最好的鼓励。

OTP输入框通常用于短信验证码、邮箱验证码等场景,一般由多个独立的输入框组成,用户输入一位数字后焦点自动跳转到下一个输入框,删除内容时焦点自动回退,同时支持粘贴完整验证码自动填充所有输入框。在React中实现这类组件,核心在于处理好输入事件和焦点状态的切换逻辑。

React中OTP输入框的事件处理与焦点管理如何实现

基础结构设计

首先我们需要定义OTP输入框的基础结构,假设我们需要一个6位的OTP输入框,每个输入框只允许输入单个数字。我们可以先定义组件的状态和输入框的引用数组,用于后续操作焦点。

import React, { useRef, useState, useEffect } from 'react';

const OtpInput = ({ length = 6, onComplete }) => {
  // 存储每个输入框的值
  const [otp, setOtp] = useState(Array(length).fill(''));
  // 存储每个输入框的ref
  const inputRefs = useRef([]);

  // 初始化ref数组
  useEffect(() => {
    inputRefs.current = inputRefs.current.slice(0, length);
  }, [length]);

  return (
    <div className="otp-container">
      {Array.from({ length }, (_, index) => (
        <input
          key={index}
          type="text"
          maxLength={1}
          value={otp[index]}
          ref={(el) => (inputRefs.current[index] = el)}
          className="otp-input"
        />
      ))}
    </div>
  );
};

export default OtpInput;

输入事件处理

输入事件需要处理用户输入单个字符的场景,当我们在一个输入框中输入内容后,需要将焦点自动切换到下一个输入框。同时需要校验输入内容是否为数字,非数字内容不录入。

const handleChange = (e, index) => {
  const value = e.target.value;
  // 只允许输入数字
  if (!/^d*$/.test(value)) return;

  // 更新对应位置的值
  const newOtp = [...otp];
  // 取最后一位输入的内容,避免粘贴多个字符时只取第一个
  newOtp[index] = value.slice(-1);
  setOtp(newOtp);

  // 如果输入了内容且不是最后一个输入框,焦点跳转到下一个
  if (value && index < length - 1) {
    inputRefs.current[index + 1].focus();
  }

  // 判断是否所有输入框都已填满,触发完成回调
  if (newOtp.every((val) => val !== '')) {
    onComplete?.(newOtp.join(''));
  }
};

handleChange函数绑定到每个输入框的onChange事件上即可实现输入后自动跳转焦点的效果。

键盘事件处理

除了输入事件,还需要处理键盘的删除键和左右方向键。当用户按下退格键且当前输入框为空时,焦点需要回退到上一个输入框;按下左方向键时焦点跳转到上一个输入框,右方向键跳转到下一个输入框。

const handleKeyDown = (e, index) => {
  const { key } = e;
  // 处理退格键
  if (key === 'Backspace') {
    // 当前输入框为空,且不是第一个输入框,回退焦点到上一个
    if (!otp[index] && index > 0) {
      inputRefs.current[index - 1].focus();
    }
  }
  // 处理左方向键
  if (key === 'ArrowLeft' && index > 0) {
    inputRefs.current[index - 1].focus();
  }
  // 处理右方向键
  if (key === 'ArrowRight' && index < length - 1) {
    inputRefs.current[index + 1].focus();
  }
};

粘贴事件处理

用户经常会复制验证码后直接粘贴到OTP输入框中,这时候需要解析粘贴的内容,自动填充到所有的输入框中。我们需要监听输入框的onPaste事件,解析粘贴的文本内容。

const handlePaste = (e) => {
  e.preventDefault();
  const pasteData = e.clipboardData.getData('text/plain').trim();
  // 过滤非数字内容,只保留数字
  const pasteNumbers = pasteData.replace(/D/g, '').slice(0, length);
  if (!pasteNumbers) return;

  const newOtp = [...otp];
  pasteNumbers.split('').forEach((num, idx) => {
    if (idx < length) {
      newOtp[idx] = num;
    }
  });
  setOtp(newOtp);

  // 粘贴后焦点跳转到最后一个有值的输入框的下一个,或者最后一个输入框
  const focusIndex = Math.min(pasteNumbers.length, length - 1);
  inputRefs.current[focusIndex].focus();

  // 判断是否所有输入框都已填满
  if (newOtp.every((val) => val !== '')) {
    onComplete?.(newOtp.join(''));
  }
};

可以将handlePaste绑定到第一个输入框或者所有输入框的onPaste事件上,这里选择绑定到每个输入框,方便用户在任何输入框粘贴都能触发解析逻辑。

完整组件代码

将上述所有逻辑整合后,完整的OTP输入框组件代码如下:

import React, { useRef, useState, useEffect } from 'react';
import './OtpInput.css'; // 引入样式文件

const OtpInput = ({ length = 6, onComplete }) => {
  const [otp, setOtp] = useState(Array(length).fill(''));
  const inputRefs = useRef([]);

  useEffect(() => {
    inputRefs.current = inputRefs.current.slice(0, length);
    // 初始时聚焦第一个输入框
    if (inputRefs.current[0]) {
      inputRefs.current[0].focus();
    }
  }, [length]);

  const handleChange = (e, index) => {
    const value = e.target.value;
    if (!/^d*$/.test(value)) return;

    const newOtp = [...otp];
    newOtp[index] = value.slice(-1);
    setOtp(newOtp);

    if (value && index < length - 1) {
      inputRefs.current[index + 1].focus();
    }

    if (newOtp.every((val) => val !== '')) {
      onComplete?.(newOtp.join(''));
    }
  };

  const handleKeyDown = (e, index) => {
    const { key } = e;
    if (key === 'Backspace') {
      if (!otp[index] && index > 0) {
        inputRefs.current[index - 1].focus();
      }
    }
    if (key === 'ArrowLeft' && index > 0) {
      inputRefs.current[index - 1].focus();
    }
    if (key === 'ArrowRight' && index < length - 1) {
      inputRefs.current[index + 1].focus();
    }
  };

  const handlePaste = (e) => {
    e.preventDefault();
    const pasteData = e.clipboardData.getData('text/plain').trim();
    const pasteNumbers = pasteData.replace(/D/g, '').slice(0, length);
    if (!pasteNumbers) return;

    const newOtp = [...otp];
    pasteNumbers.split('').forEach((num, idx) => {
      if (idx < length) {
        newOtp[idx] = num;
      }
    });
    setOtp(newOtp);

    const focusIndex = Math.min(pasteNumbers.length, length - 1);
    inputRefs.current[focusIndex].focus();

    if (newOtp.every((val) => val !== '')) {
      onComplete?.(newOtp.join(''));
    }
  };

  return (
    <div className="otp-container">
      {Array.from({ length }, (_, index) => (
        <input
          key={index}
          type="text"
          maxLength={1}
          value={otp[index]}
          ref={(el) => (inputRefs.current[index] = el)}
          onChange={(e) => handleChange(e, index)}
          onKeyDown={(e) => handleKeyDown(e, index)}
          onPaste={handlePaste}
          className="otp-input"
        />
      ))}
    </div>
  );
};

export default OtpInput;

基础样式示例

为了让OTP输入框看起来更美观,可以添加如下基础样式:

.otp-container {
  display: flex;
  gap: 10px;
  justify-content: center;
  align-items: center;
}

.otp-input {
  width: 40px;
  height: 40px;
  text-align: center;
  font-size: 18px;
  border: 1px solid #ccc;
  border-radius: 4px;
  outline: none;
}

.otp-input:focus {
  border-color: #1677ff;
  box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2);
}

使用方式

在业务组件中引入OtpInput组件,传入lengthonComplete回调即可使用:

import React from 'react';
import OtpInput from './OtpInput';

const App = () => {
  const handleOtpComplete = (otp) => {
    console.log('输入的验证码是:', otp);
    // 这里可以调用后端接口验证验证码
  };

  return (
    <div className="app">
      <h3>请输入6位验证码</h3>
      <OtpInput length={6} onComplete={handleOtpComplete} />
    </div>
  );
};

export default App;

注意事项

  • 输入框的type可以设置为number,但部分浏览器会显示上下调节箭头,更推荐用text配合正则校验限制输入内容。
  • 移动端输入时,可以设置inputModenumeric,调起数字键盘,提升用户输入体验。
  • 如果需要支持验证码自动填充(如短信验证码自动填充),可以结合 useEffect监听系统填充的验证码内容,自动更新输入框状态。

ReactOTP_input焦点管理事件处理修改时间:2026-06-29 00:48:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。