You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:16:03