如何在Material UI中实现粘贴数字自动拆分填充到多个独立文本框
React + Material UI 实现OTP粘贴自动拆分填充方案
核心实现逻辑
- 监听输入框的
paste粘贴事件,拦截默认粘贴行为 - 过滤粘贴内容中的非数字字符,按长度拆分填充到对应输入框
- 填充完成后自动调整焦点位置
具体修改步骤
1. 定义粘贴事件处理函数
在组件内部新增handlePaste方法,处理剪贴板内容的读取、过滤、拆分逻辑:
const handlePaste = (e: React.ClipboardEvent, index: number) => { // 阻止默认粘贴,避免整串内容直接填入当前输入框 e.preventDefault(); // 获取剪贴板文本内容 const pastedText = e.clipboardData.getData('text'); // 过滤所有非数字字符,只保留数字 const pureNumbers = pastedText.replace(/[^0-9]/g, ''); if (!pureNumbers) return; const newOtpArr = [...otpArr]; // 从当前触发粘贴的输入框位置开始填充 for (let i = 0; i < pureNumbers.length; i++) { const targetIndex = index + i; // 超出OTP总长度就停止填充 if (targetIndex >= otpArr.length) break; newOtpArr[targetIndex] = pureNumbers[i]; } setOtpArr(newOtpArr); // 填充完成后自动跳转到最后一个填充位置的下一个输入框 const lastFilledIndex = Math.min(index + pureNumbers.length - 1, otpArr.length - 1); if (lastFilledIndex < otpArr.length - 1) { inputRefs.current[lastFilledIndex + 1]?.current?.focus(); } };
2. 修正输入框Ref类型
原代码中Ref声明为HTMLDivElement类型,不符合TextField inputRef指向原生输入框的实际类型,调整为:
const inputRefs = useRef([ React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>() ])
3. 绑定粘贴事件到输入框
给每个NumberTextField新增onPaste属性绑定处理函数即可。
完整修改后代码
const [otpArr, setOtpArr] = useState<string[]>(['', '', '', '', '', '']) const inputRefs = useRef([ React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>(), React.createRef<HTMLInputElement>() ]) const handlePaste = (e: React.ClipboardEvent, index: number) => { e.preventDefault(); const pastedText = e.clipboardData.getData('text'); const pureNumbers = pastedText.replace(/[^0-9]/g, ''); if (!pureNumbers) return; const newOtpArr = [...otpArr]; for (let i = 0; i < pureNumbers.length; i++) { const targetIndex = index + i; if (targetIndex >= otpArr.length) break; newOtpArr[targetIndex] = pureNumbers[i]; } setOtpArr(newOtpArr); const lastFilledIndex = Math.min(index + pureNumbers.length - 1, otpArr.length - 1); if (lastFilledIndex < otpArr.length - 1) { inputRefs.current[lastFilledIndex + 1]?.current?.focus(); } }; // 渲染部分 {otpArr.map((x, index) => ( <NumberTextField inputRef={inputRefs.current[index]} variant='outlined' size='small' id={`otp-${index}`} value={x} key={index} onChange={(e: any) => { const temp = [...otpArr] temp[index] = e.target.value setOtpArr(temp) if ((index < otpArr.length - 1) && e.target.value.length === 1) { inputRefs.current[index + 1]?.current?.focus() } }} onPaste={(e) => handlePaste(e, index)} inputProps={{ maxLength: 1 }} style={{ width: '3rem', direction: 'ltr', marginTop: '3rem', marginRight: '0.5rem' }} /> ))}
额外优化建议
可以新增退格键跳转逻辑:当输入框内容为空时按下退格键,自动聚焦到上一个输入框,优化手动输入体验。
内容的提问来源于stack exchange,提问作者Banafshe Alipour
相关产品推荐
相关产品推荐

