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> ); }
关键修改点
- 输入框自动聚焦:使用
useRef存储每个输入框的DOM实例,当当前输入框内容达到3位时,自动聚焦到下一个输入框。 - 粘贴内容拆分:新增
onPaste事件处理函数,拦截粘贴操作,将内容拆分到三个输入框,并根据内容长度自动聚焦到对应位置。 - 输入内容净化:对输入和粘贴的内容进行数字过滤和长度截断,确保每个输入框只保留有效字符。
你的CSS代码无需修改,保持原有样式即可。
内容的提问来源于stack exchange,提问作者zeak
相关产品推荐
相关产品推荐

