在表单验证中,blur 后立即调用 focus() 会重新触发 blur,导致 chrome 等浏览器出现无限弹窗循环;正确做法是将 focus() 推入任务队列末尾,用 settimeout(fn, 0) 实现异步聚焦。
在表单验证中,blur 后立即调用 focus() 会重新触发 blur,导致 chrome 等浏览器出现无限弹窗循环;正确做法是将 focus() 推入任务队列末尾,用 settimeout(fn, 0) 实现异步聚焦。
当我们在 blur 事件处理函数中直接调用 element.focus(),浏览器会在焦点返回的瞬间再次触发该元素的 blur(尤其在 Chrome 中表现明显),进而形成「alert → focus → blur → alert…」的死循环。根本原因在于:同步聚焦会立即引发新一轮焦点状态变更,而当前事件循环尚未退出,导致事件重入。
解决方案是打破同步执行链,将 focus() 操作延迟至当前宏任务结束后、下一个事件循环开始时执行。setTimeout(fn, 0) 正是实现这一目标的标准方式——它将回调推入宏任务队列,确保 DOM 状态已稳定、当前 blur 流程彻底结束后再恢复焦点。
以下是修复后的完整代码示例:
$('#selPregnant').on('blur', function() {
const gender = $("#selGender :selected").val();
const pregnantValue = $("#selPregnant").val();
if (gender === "F" && pregnantValue === '') {
alert('If the individual is female, the pregnancy question MUST be answered.');
// ✅ 使用 setTimeout 实现异步聚焦,避免 blur 再次触发
setTimeout(() => $('#selPregnant').focus(), 0);
return false;
}
});⚠️ 注意事项:
- 不要使用 setImmediate(仅 IE 支持)或 Promise.resolve().then()(属于微任务,在某些场景下仍可能过早触发);
- 若项目已使用现代框架(如 React/Vue),建议改用受控组件 + 表单级校验,而非依赖原生 focus/blur 交互;
- alert() 会阻塞 UI 线程,影响体验;生产环境推荐替换为非模态提示(如 Toast 或内联错误消息)+ 自动聚焦,进一步提升可用性。
总结:blur 中需聚焦时,务必通过 setTimeout(..., 0) 异步化操作——这是绕过浏览器焦点事件重入机制的可靠模式,兼具兼容性与可维护性。

















