import React, { useEffect, useState, useRef } from 'react'; import styles from './styles.module.scss'; import { APP_OPT_LENGTH } from '@constants/app'; const MobileCodeInput = ({ length = APP_OPT_LENGTH, onChange, className = '', onFocus, onBlur }) => { const inputLength = Number.isInteger(length) && length > 0 ? length : APP_OPT_LENGTH; // 初始化一个长度为6的空字符串数组 const [code, setCode] = useState(new Array(inputLength).fill('')); const [active, setActive] = useState(false); // 用于存储每个输入框的DOM引用,方便控制焦点 const inputRefs = useRef([]); useEffect(() => { setCode(new Array(inputLength).fill('')); setActive(false); inputRefs.current = inputRefs.current.slice(0, inputLength); }, [inputLength]); // 新增:处理聚焦 const handleFocus = (index) => { onFocus?.(index); // 传回聚焦的输入框索引 }; // 新增:处理失焦 const handleBlur = () => { onBlur?.(); }; const handleCodeChanged = (newCode) => { const completed = newCode.every((char) => char !== '') && newCode.length === inputLength; setActive(completed); onChange?.(newCode.join('')); } // 处理输入变化 const handleChange = (index, e) => { const value = e.target.value; // 仅允许输入数字 if (!/^\d*$/.test(value)) return; const newCode = [...code]; // 如果用户快速输入覆盖了原数字,取最后一位 newCode[index] = value.substring(value.length - 1); setCode(newCode); // 如果当前输入框有值,且不是最后一个,则焦点自动移向下一个 if (value && index < inputLength - 1) { inputRefs.current[index + 1]?.focus(); } // 检查是否所有格子都已填满,如果是则触发回调 handleCodeChanged(newCode); }; // 处理键盘按键事件(主要处理 Backspace 逻辑) const handleKeyDown = (index, e) => { // 当按下退格键,且当前格子为空时,焦点自动移向上一个格子 if (e.key === 'Backspace' && !code[index] && index > 0) { inputRefs.current[index - 1]?.focus(); } }; // 处理粘贴事件 const handlePaste = (e) => { e.preventDefault(); // 获取粘贴板中的文本 const pastedData = e.clipboardData.getData('text/plain').trim(); // 过滤非数字字符,并截取到指定长度 const cleanData = pastedData.replace(/\D/g, '').slice(0, inputLength); if (!cleanData) return; const newCode = new Array(inputLength).fill(''); const pastedArray = cleanData.split(''); // 将粘贴的数据分配到数组中 pastedArray.forEach((char, i) => { newCode[i] = char; }); setCode(newCode); // 计算粘贴后焦点应该停留在哪个输入框 const focusIndex = pastedArray.length < inputLength ? pastedArray.length : inputLength - 1; inputRefs.current[focusIndex]?.focus(); // 如果粘贴的长度刚好等于所需长度,触发回调 handleCodeChanged(newCode) }; return (
{ code.map((value, index) => ( (inputRefs.current[index] = el)} type="text" inputMode="numeric" // 在移动端唤起数字键盘 value={value} onChange={(e) => handleChange(index, e)} onKeyDown={(e) => handleKeyDown(index, e)} onPaste={handlePaste} className={`${styles.input_box} ${active ? styles.active : ''}`} onFocus={() => handleFocus(index)} // 新增 onBlur={handleBlur} // 新增 /> ))}
); }; export default MobileCodeInput;