背景
笔者这段时间在做登陆相关的业务,在没有产品的情况下,我们需要做一个比较流畅,并且符合直觉的登陆校验逻辑,在我做完之后,我想要来分析一下登陆中的“校验逻辑”。
至于具体的前后端接口逻辑,我就不详细说了。
前端这边主要用的是 antd。
具体逻辑
我们先来盘点一下,实现一个登陆页面,前端在校验方面,需要做哪些事情:
-
校验不合规范的手机号格式
-
获取验证码的时候,会有 60s 的间隔,这个间隔需要前端来实现,哪怕是在我们刷新页面的时候,我们也需要保持时间流动。
实现逻辑
- 那么对于“手机号格式”这个事情来说,他会有一个符合规范的标准,这个标准,我们当然是通过正则来实现的。
我们可以看到实现如下:
// utils 检测手机号是否合格
const regex = /^1[3-9][0-9]{9}$/;
export const isRightNumber = (val: string) => {
return regex.test(val);
};
我们通过导出这个函数,放在我们的自定义校验规则里。
但是我实际在做这个功能的时候发现,如果我把他放在自定义校验规则里,就会一个情况:
“我每输入一个数字,就会产生一次校验。”
这种情况显然不符合直觉,这个问题的解决是通过给<FormItem/> 设置 validateTrigger={['onBlur', 'onSubmit']}
这样我们就可以把时机规定到 onBlur 的时候
但是还是会有一种场景:
“如果说,已经出现了错误,然后我修改手机号,只有在onBlur的时候才能去掉提示红框+提示文字”
所以我们需要客制化的处理这种情况:
<FormItem
name='xxx'
rules={[validatePhoneNumberRule]}
validateTrigger={['onBlur', 'onSubmit']}
validateStatus={!isTyping && !validatePhoneNumber(form.getFieldValue('xxx') as string) ? 'error' : ''}
help={
!isTyping && !validatePhoneNumber(form.getFieldValue('xxx') as string)
? form.getFieldsError(['xxx'])[0]?.errors[0]
: ''
}>
- 这里的
validateStatus就是我们红框的状态 - 而
help就是红框下具体的提示文案
至此,“校验不合规范的手机号格式”这一部分我们就已经实现了。
- 对于获取验证码的逻辑来说,我们需要处理 60s 的时间间隔
具体来说:
- 需要定义结束时间点与剩余时间
- 需要实现一个 hooks 去更新剩余时间
- 需要提供一个 func,后续第二次获取验证码
对于第一个逻辑来说:
const [endTime, setEndTime] = useState<Date>(() => {
const storedEndTime = localStorage.getItem('endTime');
return storedEndTime ? new Date(storedEndTime) : new Date(Date.now());
});
const [secondsLeft, setSecondsLeft] = useState<number>(() => {
const currentTime = new Date().getTime();
const endTimeVal = new Date(endTime).getTime();
return Math.max(0, Math.floor((endTimeVal - currentTime) / 1000));
});
对于第二部分逻辑来说:
// 更新剩余时间
useEffect(() => {
const tick = () => {
const currentTime = Date.now();
const remainingTime = Math.max(0, (Number(endTime) - currentTime) / 1000);
setSecondsLeft(Math.floor(remainingTime));
if (remainingTime === 0) {
clearInterval(intervalId);
}
};
const intervalId = setInterval(tick, 1000);
tick();
return () => clearInterval(intervalId);
}, [endTime]);
对于第三部分逻辑来说:
// 重置倒计时
const resetCountdown = useCallback(() => {
const newEndTime = new Date(Date.now() + 60000);
setEndTime(newEndTime);
localStorage.setItem('endTime', newEndTime.toISOString());
setSecondsLeft(60);
}, []);
具体使用的话,展示倒计时是使用 {secondsLeft},而重置倒计时则是resetCountdown()
至此,验证码登陆业务校验逻辑的剖析就已经结束了~