尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Vben-Admin 框架中验证码倒计时动态更新解决方案

Vben-Admin 框架中验证码倒计时动态更新解决方案 Vben-Admin 框架中验证码倒计时动态更新解决方案一、Vben-Admin 是什么Vben-Admin是一个基于Vue 3 TypeScript Vite的现代化企业级中后台管理系统框架。它提供了开箱即用的权限管理、路由配置丰富的 UI 组件库基于 Ant Design Vue 封装强大的表单、表格组件系统统一的登录/认证模块vben/common-ui其中的AuthenticationCodeLogin和VbenPinInput组件就是框架内置的验证码登录解决方案。二、为什么会出现这个需求业务场景用户登录时通过手机号 短信验证码的方式。后端接口有以下逻辑验证码未过期时→ 不重复发送短信直接返回已存在的验证码的expire_at验证码已过期或不存在时→ 生成新验证码并发送短信核心需求前端倒计时必须与后端验证码的有效期实时同步场景后端返回expire_at期望倒计时首次请求2026-08-08 14:05:005分钟后300 秒30 秒后再次请求验证码未过期2026-08-08 14:05:00不变270 秒4 分 50 秒后再次请求快过期了2026-08-08 14:05:00不变10 秒5 分钟后再次请求已过期2026-08-08 14:10:00新时间300 秒一句话用户看到的倒计时 当前验证码的真实剩余有效时间每次点击获取验证码按钮都与后端同步校验无缝续期。三、遇到的问题3.1 一开始以为handleSendCode返回值控制倒计时根据VbenPinInput的 props 定义我们以为handleSendCode的返回值会控制倒计时秒数// ❌ 直觉上以为这样就能控制倒计时handleSendCode:async(){// ... 发送验证码 ...return300;// 以为返回 300 就能倒计时 300 秒}3.2 实际测试发现返回无效当我们测试handleSendCode: async () { return 20; }时倒计时仍然显示 60 秒。3.3 查看组件源码发现真相通过查看VbenPinInput组件源码发现其内部逻辑是// VbenPinInput 组件内部简化const{maxTime60,// ← 倒计时秒数来自这里handleSendCodeasync(){},}definePropsPinInputProps();constcountdownref(0);asyncfunctionhandleSend(e:Event){awaithandleSendCode();// ← 只是执行忽略返回值countdown.valuemaxTime;// ← 直接用 maxTime 作为倒计时startCountdown();// ← 每秒减 1}结论handleSendCode的返回值完全被忽略倒计时秒数由maxTimeprops 决定。四、解决方案4.1 核心思路利用 Vue 的响应式数据特性用ref动态绑定maxTime// 1. 定义响应式变量初始 60 秒constmaxTimeref(60);// 2. 在 handleSendCode 中更新它consthandleSendCodeasync(){constresawaitsendCodeApi({phone});if(res.data.expire_at){constsecondsgetSecondsRemaining(res.data.expire_at);maxTime.valueseconds0?seconds:60;// ✅ 更新倒计时}};// 3. 传给 VbenPinInputcomponentProps:{maxTime:maxTime,// ← 响应式绑定值变了组件自动更新}4.2 完整代码script langts setup import { computed, ref } from vue; import { AuthenticationCodeLogin, z } from vben/common-ui; import { $t } from vben/locales; import { message } from ant-design-vue; import { sendCodeApi } from #/api; // 1. 响应式倒计时秒数 const maxTime ref(60); // 2. 计算剩余秒数 const getSecondsRemaining (dateString: string) { const diffMs new Date(dateString).getTime() - new Date().getTime(); return Math.floor(diffMs / 1000); }; // 3. 发送验证码 const handleSendCode async () { try { const res await sendCodeApi({ phone: currentPhone }); if (res.code 0) { if (res.data.expire_at) { const seconds getSecondsRemaining(res.data.expire_at); // ✅ 关键更新响应式变量 maxTime.value seconds 0 ? seconds : 60; } } } catch (error) { // 错误处理... } }; // 4. 表单配置 const formSchema computed((): VbenFormSchema[] [ { component: VbenInput, fieldName: phone, // ... }, { component: VbenPinInput, fieldName: code, componentProps: { codeLength: 6, maxTime: maxTime, // ✅ 响应式绑定 createText: (countdown: number) { return countdown 0 ? ${countdown} 秒后重发 : 获取验证码; }, handleSendCode: handleSendCode, }, // ... }, ]); /script4.3 数据流图用户点击按钮 │ ▼ handleSendCode() │ ▼ sendCodeApi() → 后端返回 { expire_at } │ ▼ getSecondsRemaining(expire_at) → 计算剩余秒数 │ ▼ maxTime.value 剩余秒数 ← 响应式更新 │ ▼ VbenPinInput 内部 countdown.value maxTime ← 组件收到新值 │ ▼ 倒计时按新的秒数开始运行五、总结项目内容框架Vben-Admin 的vben/common-ui认证模块组件VbenPinInput验证码输入倒计时误区误以为handleSendCode返回值控制倒计时真相maxTimeprops 才是倒计时秒数的唯一来源解法用ref响应式绑定maxTime在handleSendCode中动态更新效果倒计时始终与后端expire_at保持同步
返回列表