如何阻止.focusout()事件多次触发?附问题复现示例
解决focusout事件切换input时触发循环的问题
嘿,这个问题我之前也碰到过!本质原因是两个点:focusout的冒泡特性,加上alert弹窗会强制抢占焦点,打乱了正常的焦点切换流程。
问题到底出在哪?
当你从第一个input切换到第二个input时,实际的事件流程是这样的:
- 第一个input失去焦点,触发它的
focusout事件,这个事件会冒泡到body上的监听器,于是alert弹出来。 - 但alert一出现就会立刻抢走页面的所有焦点——这时候第二个input还没来得及真正获取焦点,就因为alert的出现被迫失去焦点,于是又触发一次body上的
focusout,alert再次弹出,直接形成死循环。
给你几个可行的解决方案:
方案1:改用不冒泡的blur事件
blur事件不会向上冒泡,只会在触发它的那个input元素上生效,这样就不会因为冒泡引发后续的连锁反应。修改后的代码很简单:
$('body').on('blur', 'input', function(){ alert('test'); });
jQuery的事件委托对blur是支持的,不用担心绑定失效的问题。
方案2:通过relatedTarget判断焦点去向
如果必须要用focusout(比如需要冒泡特性处理其他元素),可以利用事件对象的relatedTarget属性,判断失去焦点后,焦点是不是转移到了页面内的另一个input上。如果是,就跳过执行alert:
$('body').on('focusout', 'input', function(e){ // 只有当焦点完全离开input元素(比如点空白、切标签页)时才触发 if (!e.relatedTarget || !$(e.relatedTarget).is('input')) { alert('test'); } });
这个方案能精准控制触发时机,既保留focusout的特性,又避免循环。
方案3:换掉alert,用不抢焦点的提示方式
alert的强制焦点抢占是循环的直接导火索,如果换成console日志或者页面内的提示元素,自然就不会有这个问题了:
$('body').on('focusout', 'input', function(){ console.log('test'); // 或者用页面内的提示框: // $('.tip').text('输入框失去焦点啦').fadeIn().delay(2000).fadeOut(); });
总结
如果不需要冒泡特性,方案1最省心;如果要保留focusout的功能,方案2是最优解;如果只是测试用,方案3也能快速解决问题。
内容的提问来源于stack exchange,提问作者Pa3k.m
相关产品推荐
相关产品推荐

