代码为何触发两次循环?多类选择器绑定的技术疑问
为什么点击按钮会触发两次循环?事件冒泡是关键原因!
嘿,你的怀疑完全站得住脚!这种点击后console.log执行两次的情况,十有八九是事件冒泡在搞鬼——因为你同时给.wrapper和.surround这两个容器绑定了点击监听,而如果这两个容器在DOM结构上存在嵌套关系(比如.wrapper是.surround的子元素,或者反过来),点击按钮时事件会沿着DOM树向上传播,同时触发两个容器的监听函数。
问题根源:事件冒泡的机制
当你点击.bet-button时,点击事件不会只停留在按钮本身,而是会从按钮开始,依次向上触发它所有父元素的点击事件。举个例子:
如果你的DOM结构是:
.surround→.wrapper→.bet-button
那么点击按钮时,事件会先触发.wrapper的监听,接着冒泡到.surround的监听,导致两次console.log输出。
快速验证你的猜测
你可以在两个监听函数里打印event.currentTarget,看看是不是两个不同的容器被触发了:
// .wrapper的监听 $('.wrapper').on('click', '.bet-button', function(e) { console.log('触发容器:', e.currentTarget); // 应该输出.wrapper元素 // 你的校验逻辑 }); // .surround的监听 $('.surround').on('click', '.bet-button', function(e) { console.log('触发容器:', e.currentTarget); // 应该输出.surround元素 // 你的校验逻辑 });
如果两次输出的容器不同,就坐实了是事件冒泡导致的重复触发。
两种靠谱的替代写法
写法1:阻止事件冒泡(适合保留容器监听的场景)
在子容器的监听函数里阻止事件继续传播,这样就不会触发父容器的监听了:
// 监听.wrapper内的按钮 $('.wrapper').on('click', '.bet-button', function(e) { // 校验awayVal和homeVal的逻辑 console.log('wrapper内按钮点击'); e.stopPropagation(); // 阻止事件冒泡到上层的.surround }); // 监听.surround内的按钮(排除.wrapper里的) $('.surround').on('click', '.bet-button', function(e) { // 如果点击的按钮在.wrapper里,直接返回 if ($(e.target).closest('.wrapper').length) return; // 校验backAwayVal和backAwayHome的逻辑 console.log('surround内按钮点击'); });
写法2:直接监听按钮,通过父容器区分逻辑(更简洁)
放弃给容器绑定监听,直接给所有.bet-button绑定点击事件,然后通过closest()方法判断按钮属于哪个容器,再执行对应的校验:
$('.bet-button').on('click', function() { const $btn = $(this); // 判断按钮是否在.wrapper内 if ($btn.closest('.wrapper').length) { // 校验awayVal和homeVal console.log('执行wrapper对应的校验'); } // 判断按钮是否在.surround内且不在.wrapper内 else if ($btn.closest('.surround').length) { // 校验backAwayVal和backAwayHome console.log('执行surround对应的校验'); } });
这种写法不需要担心事件冒泡问题,逻辑更直观,也更易维护。
内容的提问来源于stack exchange,提问作者Bkes
相关产品推荐
相关产品推荐

