1 效果
大致的功能有:
- 进入页面自动发送验证码
- 验证码输入完成后,触发验证码校验
- 可以手动输入或者删除验证码
效果图如下:
2 输入框实现
验证码输入框部分,主要使用一个input
加6个div
来展示,在页面上需要将input
隐藏掉,6个div
显示输入框中的验证码数字,基本实现如下:
import React, {
useState, useEffect, useRef } from "react";
import "./index.css";
const CodeInput = (props) => {
/**
* vertifyCode:验证码
* onChange:验证码改变的回调
* onComplete:验证码输入完成后的回调
*/
const {
vertifyCode = "", onChange, onComplete } = props;
const [codeArray, setCodeArray] = useState([]); // 用来存放验证码的数组
const [isFocus, setIsFocus] = useState(false); // 判断是否获取焦点
const inputList = [...Array(6)].map((item, index) => index); // 生成模拟输入框数组[0,1,2,3,4,5]
const inputRef = useRef(null); // 绑定input输入框
// 获取焦点事件
const handleInputFocus = () => {
inputRef.current?.focus(); // 为输入框聚焦
setIsFocus(true);
};
// 获取验证码
useEffect(() => {
setCodeArray(vertifyCode.split(""));
}, [vertifyCode]);
// 当验证码6位时,触发完成事件,校验验证码
useEffect(() => {
if (vertifyCode.length !== 6) return; // 验证码不足6位,不触发校验事件
onComplete && onComplete(vertifyCode);
}, [vertifyCode, onComplete]);
// 验证码改变事件
const handleChange = (e) => {
if (e.target.value) {
// 获取当前输入的数字
let val = e.target.value.replace(/[^\d]/g, ""); // 只保留数字
onChange?.(val);
} else {
onChange?.("");
}
};
// 失去焦点
const handleBlur = () => {
setIsFocus(false);
};
// 获取焦点
const handleFocus = () => {
setIsFocus(true);
};
// 默认聚焦input输入框,每次进入都执行
useEffect(() => {
handleInputFocus();
});
return (
<div className="code-input-container" onClick={
handleInputFocus}>
{
/* 验证码数字显示部分 */}
<div className="number-box">
{
inputList.map((item, index) => {
return (
<div
className="input-item"
key={
index}
style={
{
// 当验证码的长度等于item时,表示当前正在等待下一位的输入,输入框变色
border: `1px solid ${
item === codeArray.length && isFocus ? "orange" : "#D9D9D9"
}`,
}}
>
{
codeArray[item]}
</div>
);
})}
</div>
{
/* 输入框,用样式隐藏不显示 */}
<input
type="number" // 数字类型输入框
inputMode="numeric" // 可以弹起数字键盘
maxLength={
6} // 最大长度是6
className="input-value"
value={
vertifyCode} // value值为输入的验证码
ref={
inputRef}
onChange={
handleChange} // 验证码改变事件
onBlur={
handleBlur} // 失去焦点事件
onFocus={
handleFocus} // 聚焦事件
/>
</div>
);
};
export default CodeInput;
基本样式如下:
/* 验证码显示框 */
.number-box {
display: flex;
justify-content: space-between;
}
/* 每一个验证码输入框的样式 */
.input-item {
margin-right: 15px;
width: 43px;
height: 45px;
display: flex;
justify-content: center;
color: #141414;
font-size: 24px;
line-height: 45px;
font-weight: 500;
}
/* 最后一个验证码输入框margin-right为0 */
.input-item:last-child {
margin-right: 0px;
}
/* 将input输入框隐藏看不见 */
.input-value {
margin-left: -750px;
position: absolute;
z-index: -99;
opacity: 0;
}
3 整体实现
在整体页面部分中,需要使用useState
来存放输入的验证码,并传给验证码输入框,基本代码如下:
import React, {
useState, useEffect } from "react";
import CodeInput from "./CodeInput"; // 导入验证码输入框
import "./index.css";
const VertificationCode = () => {
const [vertifyCode, setVertifyCode] = useState(""); // 保存当前输入的验证码
// 验证码改变事件
const handleChange = (vertifyCode) => {
console.log("当前输入了:", vertifyCode);
setVertifyCode(vertifyCode); // 更新验证码
};
// 验证码输入完成后进行校验
const handleComplete = (vertifyCode) => {
// 验证码输入后验证逻辑
console.log("验证码输入完毕", vertifyCode);
};
// 请求发送验证码
const sendVertifyCode = () => {
// 发送验证码的逻辑
console.log("验证码已发送");
};
// 重新发送方法
const handleSend = () => {
// 重发验证码逻辑,一般情况为:60s倒计时后重新可以再次发送
};
useEffect(() => {
// 刚进入页面时,发送验证码
sendVertifyCode();
}, []);
return (
<div className="root">
<div className="title">输入验证码</div>
<div className="sub-title-container">
<div className="sub-title">已发送验证码至</div>
<span className="phone-number">+86 123****0000</span>
</div>
<div className="code">
<CodeInput
vertifyCode={
vertifyCode}
onChange={
handleChange}
onComplete={
handleComplete}
/>
</div>
<div className="send-btn" onClick={
handleSend}>
重新发送
</div>
</div>
);
};
export default VertificationCode;
基本样式如下:
/* 整体容器样式 */
.root {
width: 100%;
}
/* 标题 输入验证码 */
.title {
font-size: 24px;
margin: 60px 20px 0;
color: #141414;
font-weight: 500;
line-height: 32px;
}
/* 描述 已发送验证码至XXX */
.sub-title-container {
margin: 10px 20px 0;
font-size: 14px;
line-height: 17px;
}
/* 联系方式 */
.phone-number {
color: #141414;
letter-spacing: 0;
}
/* 已发送验证码 */
.sub-title {
display: inline-block;
color: #83898f;
letter-spacing: 0;
margin-right: 4px;
}
/* 验证码输入部分 */
.code {
height: 45px;
margin: 40px 20px 0;
}
/* 重新发送 */
.send-btn {
width: 116px;
height: 20px;
color: orange;
font-weight: 500;
margin: 20px;
font-size: 16px;
line-height: 20px;
}