React实现短信验证码输入组件
在日常开发中,短信验证码输入是一个非常常见的需求。今天和大家分享一个基于React实现的验证码输入组件,它具有以下特点:
- 支持6位数字验证码输入
- 自动聚焦下一个输入框
- 支持回退删除
- 支持移动端输入
- 输入完成后自动触发回调
组件代码实现
const SmsVerify = ({ onComplete, onChange }: { onComplete?: (code: string) => void onChange?: (value: string) => void }) => { const [code, setCode, getCode] = useGetState<string[]>([]) const inputRefs = useRef<(HTMLInputElement | null)[]>([]) useEffect(() => { const seat = new Array(6).fill('') setCode(seat) }, []) useEffect(() => { // 当所有格子都填满时触发完成回调 if (code.every((v) => v !== '') && onComplete) { onComplete(code.join('')) } onChange?.(code.join('')) }, [code, onComplete]) const handleOnChange = ({ value, index }: { value: string | number index: number }) => { // 将value转换为字符串并确保只保留数字 const stringValue = String(value).replace(/[^0-9]/g, '') // 只取第一个数字 const singleDigit = stringValue.slice(0, 1) if (singleDigit) { setCode( produce((draft) => { draft[index] = singleDigit }) ) // 自动聚焦下一个输入框 if (index < 5) { inputRefs.current[index + 1]?.focus() } } } const handleKeyDown = ( e: React.KeyboardEvent<HTMLInputElement>, index: number ) => { if (e.key === 'Backspace') { // 当前格子为空时,删除键将焦点移到上一个输入框 setCode( produce((draft) => { draft[index] = '' }) ) inputRefs.current[index - 1]?.focus() e.preventDefault() } } return ( <div className="sms-verify"> <div className="flex gap-[0.1rem]"> {code.map((value, index) => { return ( <InputNumber className={classNames('text-[0.4rem]', { 'has-content': value })} ref={(el) => { if (el) { inputRefs.current[index] = el } }} type="tel" value={value} key={'T-' + index} controls={false} onKeyDown={(e) => handleKeyDown(e, index)} onInput={(value) => handleOnChange({ value: value || '', index }) } /> ) })} </div> </div> ) }
关键点
- 使用 type="tel" 调起数字键盘,如果把type类型换成number,在移动端会有兼容性问题,用户可以输入特殊字符和中文,用type="tel",则不会有这个情况
- onInput 代替onChange事件,如果用onChange,最后一个输入框可以无限制输入内容,删除内容时,无法删除输入的全部内容,而使用onInput 时,能一次性删除当前输入框所有内容
愿你走出半生,归来仍是少年