一、概述
现在项目中一般涉及到用户登录都支持了手机验证码登录,本篇文章就是给大家分享一下胡哥封装的一个验证码组件rc-codebox
,采用的是React Hooks的方式来开发的。
二、验证码组件介绍与安装
rc-codebox是基于react hooks的验证码组件,支持特性如下:
API
Name | Description | Type | Default |
len | 验证码的位数 | number |
6 |
onChange | 验证码改变时的callback | (code: string) => void |
-- |
className | 自定义类名 | string |
-- |
autoFocus | 是否自动获取焦点 | boolean |
true |
安装:
yarn add rc-codebox
使用:
import React, { useState } from 'react'; import { CodeBox } from 'rc-codebox'; export default () => { // 初始化code变量,接收验证码 const [code, setCode] = useState(''); /** * @method onChange * @description 检测用户输入的验证码 */ const onChange = (code) => { setCode(code); }; return ( <div> <h3>现在输入的code是:{code}</h3> {/* 渲染codeBox,指定验证码长度,自动获取焦点,检测用户输入验证码时的onChange事件 */} <CodeBox len={6} onChange={onChange} autoFocus={true}></CodeBox> </div> ); };
三、验证码组件设计与开发
rc-codebox验证码组件是基于组件开发工具dumi开发的。
在这里必须给dumi
吹一波,dumi-为组件开发场景而生的文档工具,有几个非常优秀的特点:
- API文档自动生成,这个功能个人感觉太棒了,直接根据组件内部注释、TypeScript类型描述自动生成API文档,始终保持如一。免去了开发完组件还得写文档的烦恼,对程序员简直不要太好~
- 丰富的Markdown扩展,可以方便的渲染组件demo,支持文档编写、管理,主题可以定制多个
搭建组件项目:
# 初始化一个站点模式的组件库开发脚手架 - 当将项目推送到github时可以使用相关配置生成一个站点 yarn create @umijs/dumi-lib --site
验证码组件开发
import React, { useRef, useEffect } from 'react'; import './index.less'; interface CodeBoxProps { /** * @description 验证码的位数 * @default 6 */ len?: number; /** * @description 验证码改变时的callback */ onChange?: (code: string) => void; /** * @description 自定义类名 * */ className?: string; /** * @description 是否自动获取焦点 * @default true */ autoFocus?: boolean; } export function CodeBox(props: CodeBoxProps) { // 配置相关默认值 const { len = 6, onChange, className = '', autoFocus = true } = props; // 输入框数组 const inputArr = new Array(len).fill(''); // 输入框ref const inputRefs = useRef<any>([]); /** * @method getRef * @description 获取input的ref */ const getRef = (dom: any) => { if (inputRefs?.current?.length === len) { return; } inputRefs.current.push(dom); }; /** * @method onInputKeyDown * @method 处理input的删除事件 * @param e 事件 * @param index number input输入框对应的索引 */ const onInputKeyDown = (e: any, index: number) => { switch (e.key) { case 'Backspace': if (index > 0 && !e.target.value) { const currentInputRef = inputRefs.current[index]; currentInputRef.value = ''; const prevInputRef = inputRefs.current[index - 1]; prevInputRef.focus(); // prevInputRef.select(); e.preventDefault(); } break; } }; /** * @method onInputValueChange * @description 当输入的验证码发生变化时 * @param index number input输入框对应的索引 */ const onInputValueChange = (index: number, e: any) => { let code = ''; inputRefs.current?.forEach((ref: any) => { if (ref?.value) { code += ref?.value; } else { code += ' '; } }); // 判断是删除操作 if (index > 0 && !e.target.value) { const prevInputRef = inputRefs.current[index - 1]; prevInputRef.focus(); } // 判断是写入操作 if (index < len - 1 && e.target.value) { const nextInputRef = inputRefs.current[index + 1]; nextInputRef.focus(); } onChange && onChange(code); }; /** * @method getInputClassName * @description 动态获取每个验证码输入框的类名,增加已输入码的输入框样式 * @param index number 索引 * @returns string */ const getInputClassName = (index: number) => { const currentInputRef = inputRefs.current[index]; const value = currentInputRef?.value; const defaultClassName = 'code-box-input'; return value ? defaultClassName + ' has-string' : defaultClassName; }; useEffect(() => { // 自动获取焦点的处理 if (autoFocus) { inputRefs?.current[0].focus(); } }, [autoFocus]); return ( <div className={className ? `code-box ${className}` : 'code-box'}> {/* 渲染每一个验证码输入框 */} {inputArr.map((v, index) => { return ( <input ref={getRef} maxLength={1} className={getInputClassName(index)} key={index} type="text" onFocus={() => { inputRefs.current[index].select(); }} onKeyDown={(e) => { onInputKeyDown(e, index); }} onChange={(e) => { onInputValueChange(index, e); }} /> ); })} </div> ); } export default CodeBox;
index.less文件
.code-box { display: flex; flex-direction: row; &-input { width: 30px; margin-right: 10px; color: #333; font-size: 36px; text-align: center; border: none; border-bottom: 2px solid #ccc; outline: none; &.has-string { border-color: #575866; } } }
这里是less样式
具体效果可以点击这里的传送门查看效果!