如何在复选框点击时停止事件冒泡

209

我有一个复选框,当点击事件发生时,我想对其执行一些 Ajax 操作。然而,该复选框还位于具有自己的点击行为的容器中,当单击复选框时,我不希望运行它的点击行为。以下示例说明了我的意图:

$(document).ready(function() {
  $('#container').addClass('hidden');
  $('#header').click(function() {
    if ($('#container').hasClass('hidden')) {
      $('#container').removeClass('hidden');
    } else {
      $('#container').addClass('hidden');
    }
  });
  $('#header input[type=checkbox]').click(function(event) {
    // Do something
  });
});
#container.hidden #body {
  display: none;
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<div id="container">
  <div id="header">
    <h1>Title</h1>
    <input type="checkbox" name="test" />
  </div>
  <div id="body">
    <p>Some content</p>
  </div>
</div>

然而,我无法找到一种方法来停止事件冒泡,同时又不影响默认的点击行为(即将复选框勾选/取消勾选)。

以下两种方法都可以停止事件冒泡,但也不会改变复选框的状态:

event.preventDefault();
return false;

2
我找到了一篇关于这个问题的文章,可能对其他Stack Overflow用户有所帮助。快速提示:单击表格行触发复选框单击 - Peder Rice
9个回答

381
替换
event.preventDefault();
return false;

使用

event.stopPropagation();

event.stopPropagation()

阻止事件冒泡到父元素,避免父级处理程序通知事件的发生。

event.preventDefault()

防止浏览器执行默认操作。使用方法isDefaultPrevented可以检查是否曾经调用了该方法(在该事件对象上)。


6
由于某些原因,这对我不起作用,但返回false是有效的。 - Randy L
3
如果你正在使用.live()方法绑定事件,那么这种方法将不起作用。你需要直接使用return false; - rahul
2
这个可以使用jQuery的.on()方法来实现(live已经被弃用了)。我一开始也不知道为什么return false没有起作用。 - styfle
我花了相当长的时间才弄清楚在IE8中event.preventDefault()没有显示复选框,但在其他浏览器中运行良好。我在修复后使用preventDefault、IE8和复选框作为关键字进行谷歌搜索,最终找到了这个答案。 - signonsridhar
这个没有起作用,但是这两行代码可以(不需要返回false)--> event.preventDefault(); event.stopPropagation(); - Kugan Kumar
保留event.preventDefault()和event.stopPropagation()是解决问题的关键。否则,每次都会出现两个点击事件。我在Rails 5中使用materializecss,这可能会影响一些东西。 - Randall Coding

34

使用 stopPropagation 方法:

event.stopPropagation();

30

不要忘记IE浏览器:

if (event.stopPropagation) {    // standard
        event.stopPropagation();
    } else {    // IE6-8
        event.cancelBubble = true;
}

37
这个答案是从2012年的。在2015年请忘记IE浏览器。 - Taylan
8
这同样适用于IE9。我的IE9测试机在stopPropagation()上会出现问题,但喜欢使用cancelBubble()。遗憾的是,有些人/组织在2016年仍在使用IE9。对于我们这些有企业客户的人来说,不能忽视这一点。 - Chris Cober
我喜欢在2019年使用IE5。 - SuperUberDuper

6
使用jQuery时,您无需单独调用停止函数。您只需在事件处理程序中返回false即可。这将停止事件并取消��泡。另请参见event.preventDefault() vs. return false。来自jQuery文档的说明如下:这些处理程序可能通过调用event.stopPropagation()或返回false来防止委托处理程序触发。

6

如其他人所提到的,尝试使用stopPropagation()

还有第二个处理程序可尝试:event.cancelBubble = true;它是一个IE特定的处理程序,但至少在FF中支持。我不太了解它,因为我自己没有使用过它,但如果其他方法都失败了,这可能值得一试。


5

这是一个非常好的例子,可以帮助理解事件冒泡的概念。根据上面的答案,最终的代码如下所示。当用户点击复选框时,使用 event.stopPropagation(); 来停止事件传播到其父元素'header'。

$(document).ready(function() {
            $('#container').addClass('hidden');
            $('#header').click(function() {
                if($('#container').hasClass('hidden')) {
                    $('#container').removeClass('hidden');
                } else {
                    $('#container').addClass('hidden');
                }
            });
          $('#header input[type=checkbox]').click(function(event) {
              if (event.stopPropagation) {    // standard
                   event.stopPropagation();
               } else {    // IE6-8
                    event.cancelBubble = true;
               }
          });     
  });

2

感谢@mehras提供的代码。我只是创建了一个片段来演示它,因为我认为这将得到赞赏,并且我想找个借口尝试一下那个功能。

$(document).ready(function() {
  $('#container').addClass('hidden');
  $('#header').click(function() {
    if ($('#container').hasClass('hidden')) {
      $('#container').removeClass('hidden');
    } else {
      $('#container').addClass('hidden');
    }
  });
  $('#header input[type=checkbox]').click(function(event) {
    if (event.stopPropagation) { // standard
      event.stopPropagation();
    } else { // IE6-8
      event.cancelBubble = true;
    }
  });
});
div {
  text-align: center;
  padding: 2em;
  font-size: 1.2em
}

.hidden {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="header"><input type="checkbox" />Checkbox won't bubble the event, but this text will.</div>
<div id="container">click() bubbled up!</div>


展示如何使用事件变量的代码,谢谢。 - Moshe Binieli

2

这是我用过的一个技巧:

handleClick = e => {
    if (e.target === e.currentTarget) {
        // do something
    } else {
        // do something else
    }
}

解释:我将handleClick附加到模态窗口的背景上,但它也会在模态窗口内的每次点击时触发(因为它在背景div中)。所以我添加了条件(e.target === e.currentTarget),只有当单击背景时才满足该条件。


1
你能解释一下你的答案是如何工作的,以便未来的读者能够清楚地了解吗? - Not A Bot

1
在AngularJS中,这应该可以工作:

event.preventDefault(); 
event.stopPropagation();

这不是AngularJS,而是纯JavaScript。 - MoritzGiessmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接