在日常开发中,短信验证码输入是一个非常常见的需求。今天和大家分享一个基于React实现的验证码输入组件,它具有以下特点:
- 支持6位数字验证码输入
- 自动聚焦下一个输入框
- 支持回退删除
- 支持移动端输入
- 输入完成后自动触发回调
一、组件实现代码
const SmsVerify = ({onComplete,onChange }: {onComplete?: (code: string) => voidonChange?: (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 | numberindex: 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 (<InputNumberclassName={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 时,能一次性删除当前输入框所有内容