You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React组件多输入框处理异常:9位验证码分框输入问题

解决React拆分验证码输入框的两个异常问题

问题说明

当前实现的3个输入框拆分9位验证码组件存在两个问题:

  • 单个输入框输入满3位字符时,无法自动切换至下一个输入框
  • 将完整9位验证码粘贴至第一个输入框时,其余输入框仍为空

解决方案

通过添加输入框DOM引用、优化输入变更逻辑、新增粘贴事件处理来解决这两个问题,以下是修改后的完整代码:

import { useState, useRef } from 'react';
import { useRouter } from 'next/router';
import Button from 'your-button-component-path'; // 替换为实际Button组件路径

type SecretCode = {
  input1: string;
  input2: string;
  input3: string;
};

export default function VoucherPage() {
  const router = useRouter();
  const [secret, setSecret] = useState<string>("");
  const [inputs, setInputs] = useState<SecretCode>({
    input1: "",
    input2: "",
    input3: "",
  });
  // 存储三个输入框的DOM引用,用于自动聚焦
  const inputRefs = useRef<(HTMLInputElement | null)[]>([]);

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    // 过滤非数字字符,并限制长度不超过3位
    const cleanedValue = value.replace(/\D/g, '').slice(0, 3);
    
    setInputs((prevState) => ({
      ...prevState,
      [name]: cleanedValue,
    }));

    // 当当前输入框内容满3位时,自动聚焦下一个输入框
    if (cleanedValue.length === 3) {
      const currentIndex = parseInt(name.replace('input', '')) - 1;
      if (currentIndex < 2) {
        inputRefs.current[currentIndex + 1]?.focus();
      }
    }
  };

  const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {
    e.preventDefault();
    // 获取粘贴内容,过滤非数字并限制总长度不超过9位
    const pastedContent = e.clipboardData.getData('text').replace(/\D/g, '').slice(0, 9);
    if (!pastedContent) return;

    // 将粘贴内容拆分到三个输入框
    setInputs({
      input1: pastedContent.slice(0, 3),
      input2: pastedContent.slice(3, 6),
      input3: pastedContent.slice(6, 9),
    });

    // 根据粘贴内容长度自动聚焦到对应输入框
    if (pastedContent.length >= 6) {
      inputRefs.current[2]?.focus();
    } else if (pastedContent.length >= 3) {
      inputRefs.current[1]?.focus();
    }
  };

  const handleSubmit = () => {
    // 合并三个输入框的内容为完整验证码
    const fullCode = inputs.input1 + inputs.input2 + inputs.input3;
    setSecret(fullCode);
    // 此处添加提交逻辑,比如接口请求等
    console.log('提交的验证码:', fullCode);
  };

  return (
    <div className="top_page_container">
      <div className={styles.voucher_container}>
        <input
          ref={(el) => inputRefs.current[0] = el}
          maxLength={3}
          className={styles.voucher_input}
          name="input1"
          onChange={handleInputChange}
          onPaste={handlePaste}
          value={inputs.input1}
          type="text"
        />
        <input
          ref={(el) => inputRefs.current[1] = el}
          maxLength={3}
          className={styles.voucher_input}
          name="input2"
          onChange={handleInputChange}
          onPaste={handlePaste}
          value={inputs.input2}
          type="text"
        />
        <input
          ref={(el) => inputRefs.current[2] = el}
          maxLength={3}
          className={styles.voucher_input}
          name="input3"
          onChange={handleInputChange}
          onPaste={handlePaste}
          value={inputs.input3}
          type="text"
        />
      </div>
      <Button
        style={{ width: "16em" }}
        onClick={handleSubmit}
      >
        Submit
      </Button>
    </div>
  );
}

关键修改点

  1. 输入框自动聚焦:使用useRef存储每个输入框的DOM实例,当当前输入框内容达到3位时,自动聚焦到下一个输入框。
  2. 粘贴内容拆分:新增onPaste事件处理函数,拦截粘贴操作,将内容拆分到三个输入框,并根据内容长度自动聚焦到对应位置。
  3. 输入内容净化:对输入和粘贴的内容进行数字过滤和长度截断,确保每个输入框只保留有效字符。

你的CSS代码无需修改,保持原有样式即可。

内容的提问来源于stack exchange,提问作者zeak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:11:12