JavaScript确认框在部分系统的blur事件中陷入无限循环
聊聊你遇到的confirm框触发blur事件无限循环问题
我仔细看了你的场景:你做了个两个输入框的示例,当输入框失去焦点时弹出confirm确认框,根据用户选择决定是留在当前输入框还是切换到另一个。在自己的OS X 10.6.8笔记本上运行正常,但到了其他系统就陷入无限循环了对吧?
先贴出你的原始代码
<input type="text" id="txtTestOne" autofocus> <input type="text" id="txtTestTwo"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <script> $('#txtTestOne, #txtTestTwo').on('blur', function(e) { var retval = confirm('Do you really want to go there?'); if (!retval) { e.target.focus(); } else { e.relatedTarget.focus(); } }); </script>
为啥会出现无限循环?
核心问题出在confirm弹窗干扰了浏览器的焦点事件流程:
- 当输入框触发
blur时,你弹出confirm框,这时候浏览器会把焦点转移到弹窗上,等于输入框又一次失去焦点,再次触发blur事件 - 用户点击取消后,你调用
e.target.focus()让输入框重新聚焦,但弹窗关闭后,浏览器的焦点处理逻辑可能又会触发一次blur,这么来回就形成了死循环 - 不同浏览器和操作系统对焦点事件的处理时序不一样,这就是为啥你的Mac上正常,其他环境出问题的原因
怎么解决?加个状态锁就行
我们可以加个状态变量,标记当前是否正在处理confirm弹窗,避免重复触发blur事件:
<input type="text" id="txtTestOne" autofocus> <input type="text" id="txtTestTwo"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <script> let isHandlingConfirm = false; // 状态锁,标记是否在处理确认框 $('#txtTestOne, #txtTestTwo').on('blur', function(e) { // 如果正在处理确认框,直接返回,别重复触发 if (isHandlingConfirm) return; isHandlingConfirm = true; const userChoice = confirm('Do you really want to go there?'); if (!userChoice) { e.target.focus(); } else if (e.relatedTarget) { // 先判断目标元素是否存在,避免报错 e.relatedTarget.focus(); } // 用setTimeout延迟解锁,确保浏览器焦点事件流程走完 setTimeout(() => { isHandlingConfirm = false; }, 0); }); </script>
额外的小优化
- 加了
e.relatedTarget的存在判断:如果用户点击的是页面空白处,e.relatedTarget会是null,直接调用focus()会报错,所以先做个判断 - 用
setTimeout延迟释放锁:确保浏览器的焦点事件序列完全结束后再解锁,避免时序上的小问题
内容的提问来源于stack exchange,提问作者BobRodes
相关产品推荐
相关产品推荐

