blur事件是格式化的可靠触发点,因其在用户离开输入框时稳定触发一次,避免change的延迟漏触发和input的频繁错乱;需同步执行格式化并手动控制光标位置,兼容移动端dom更新节奏。

blur 事件是格式化的可靠触发点
用 blur 而不是 change 或 input——前者在用户明确离开输入框时稳定触发一次,后者要么延迟(change)、要么过于频繁(input),容易导致格式错乱或光标跳动。
-
change只在值真正变化后失焦才触发,用户没改内容就点别处,格式化就漏了 -
input每次按键都触发,比如把 “123” 格式化为 “12.3”,再输 “4” 就变成 “12.34” → 立刻被截断成 “12.3”,光标卡在末尾 -
blur语义准确、兼容性好,所有浏览器都支持,且不会因 DOM 变动误发
格式化逻辑必须同步执行并手动控制光标位置
纯前端格式化(如金额加逗号、手机号分段、邮箱小写)应同步完成;若不干预光标,浏览器默认会把光标移到末尾,破坏用户体验。
- 先保存当前光标位置:
const start = input.selectionStart; const end = input.selectionEnd; - 执行格式化(例如:
input.value = input.value.replace(/\D/g, '').replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');) - 格式化后恢复光标:用
setSelectionRange()把光标放回合理位置,比如在连字符后、数字中间 - 避免用
setTimeout延迟赋值——异步会导致光标重置不可控,且 blur 后再 set 的 value 可能被浏览器忽略
防抖不是必需,但网络校验要区分对待
本地格式化不需要防抖;只有涉及异步操作(如查重、远程校验)才需加载状态和节流控制。
- 金额转大写、电话补区号、日期标准化等,直接同步跑完即可
- 如果格式化依赖接口(例如“用户名是否可用”后自动补全推荐名),必须禁用提交按钮 + 显示 loading,并在 fetch.then() 中更新 value 和光标
- 此时不能只靠
blur,还得监听keydown拦截 Enter 提交,防止用户在 loading 中重复点击 - 不要对
blur加 setTimeout 包裹——它本身已是离散事件,加延迟反而让交互变卡,还可能丢失this指向
移动端软键盘收起后焦点易丢失,需额外兜底
Android WebView 和部分 iOS Safari 在 blur 后可能无法保证 input.value 已稳定,尤其配合第三方键盘时。
- 简单兜底:在
blur回调末尾加一次input.value = input.value.trim();,强制清理首尾空格 - 更稳妥做法:用
setTimeout(() => { /* 格式化逻辑 */ }, 0)微任务延后执行,确保 DOM 更新完成 - 避免在 blur 中调用
input.focus()—— 移动端会立刻弹键盘,干扰用户操作流程 - 若格式化后发现非法值(如负数金额),不要清空 input.value,而是设
input.setCustomValidity('请输入正数')并留空,让用户自己修正
blur 本身不复杂,难的是格式化过程中的光标管理、移动端兼容、以及和原生校验机制的协作。很多人卡在“格式化完了但光标飞了”或者“安卓上第一次 blur 没生效”,其实问题不在事件选错,而在没处理好 DOM 更新节奏和输入法残留行为。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











