点击「获取验证码」后立即禁用按钮并启动60秒倒计时,需绑定状态、可中断重置;倒计时仅在接口成功响应后开始,失败或页面卸载时须清理定时器并重置按钮。

点击按钮后立即禁用并显示倒计时
用户点下「获取验证码」按钮后,必须立刻禁用按钮防止重复提交,同时开始 60 秒倒计时。关键不是单纯 setTimeout,而是要绑定状态、可中断、能重置。
- 用
disabled属性禁用按钮,比仅靠 CSS 灰化更可靠(防键盘回车或屏幕阅读器触发) - 倒计时用
setInterval,但务必保存返回的 timer ID,后续调用clearInterval时要用到 - 别直接修改
button.innerText,优先用textContent避免 XSS 风险(尤其当倒计时文案含用户可控内容时) - 初始按钮文案建议存为 data 属性,比如
data-default-text="获取验证码",方便倒计时结束后还原
倒计时期间点击无效且视觉反馈明确
倒计时运行中,用户再次点击应完全无响应——不是弹提示,也不是报错,就是静默忽略。视觉上需让用户一眼看出「现在点不了」。
- 禁用状态下,CSS 加
pointer-events: none是冗余的,disabled已足够阻止 click 事件 - 用
:disabled伪类控制样式,例如opacity: 0.6; cursor: not-allowed;,不要依赖 JS 动态加 class - 避免在倒计时函数里写
if (btn.disabled) return—— 这是防御性冗余,真正该做的是:只在未禁用时才绑定 click handler,或用事件委托 + 状态判断
发送请求成功才启动倒计时,失败则重置按钮
倒计时不是点下去就开跑,必须等短信接口返回成功(HTTP 200 + 业务 code === 0)才开始。否则用户网络卡顿或后端限流失败,按钮却锁住了,体验极差。
- 把
startCountdown()调用放在fetch().then(res => res.json()).then(data => { if (data.code === 0) startCountdown(); })里,而不是 click 回调开头 - catch 块里必须调用
resetButton(),恢复按钮可点击和原始文案,否则用户卡在「60s」动弹不得 - 注意 fetch 默认不带 credentials,如需 cookie 认证,得加
{ credentials: 'include' } - 超时控制建议由后端承担,前端最多加个
AbortController防止 pending 请求堆积
页面卸载或切换标签页时自动清理定时器
用户点完按钮切到微信聊两句再回来,倒计时可能已失效(时间不准、按钮没恢复),甚至内存泄漏。必须监听生命周期主动清理。
立即学习“前端免费学习笔记(深入)”;
- 在倒计时启动时,用
addEventListener('visibilitychange', () => { if (document.hidden && timerId) clearInterval(timerId); }) - 更稳妥的做法是监听
beforeunload,但注意 Safari 对该事件限制严格,仅用于清除 timer,不做异步操作 - 别依赖
pagehide或blur—— 它们触发时机不稳定,且无法覆盖 PWA 后台运行场景 - timerId 必须是模块级变量(或闭包内可访问),不能藏在某个回调函数作用域里,否则 cleanup 时拿不到



















