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

代码为何触发两次循环?多类选择器绑定的技术疑问

为什么点击按钮会触发两次循环?事件冒泡是关键原因!

嘿,你的怀疑完全站得住脚!这种点击后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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:44:35