如何在单击子项时仅触发父单击事件

时间:2016-08-09 22:43:45

标签: javascript jquery css html5

子和父都可以点击(子可以是jQuery点击事件的链接或div)。当我点击child时,我该如何仅触发父点击事件而不触发子事件?

6 个答案:

答案 0 :(得分:60)

DOM事件阶段

事件有三个阶段:

  1. 捕获:第一阶段是“捕获”,其中事件处理程序从<window>开始调用,并通过后代向下移动到事件目标。
  2. 目标:第二阶段是调用目标上的事件侦听器时的“目标”阶段。
  3. 冒泡:第三阶段是“冒泡”,首先是处理程序监听目标的父级,然后逐步调用该元素的祖先。
  4. 事件也有一个“默认动作”,它发生在冒泡阶段之后。默认操作是浏览器定义的操作,通常对于作为事件目标的元素类型的指定类型的事件发生(例如,浏览器导航到href的{​​{1}}一个<a>,而另一种元素的click将有不同的默认操作。)

    DOM Level 3 Events draft有一个图表,以图形方式显示事件如何通过DOM传播:

    Graphical representation of an event dispatched in a DOM tree using the DOM event flow
    图片版权所有©2016 World Wide Web Consortium,(MITERCIMKeioBeihang)。 http://www.w3.org/Consortium/Legal/2015/doc-license(允许使用the license

    有关捕获和冒泡的更多信息,请参阅:“What is event bubbling and capturing?”; DOM Level 3 Events draft;或W3C DOM4: Events

    防止事件发生到孩子身上

    对于您想要的内容,要在父级之前获取事件并阻止该事件,您必须在捕获阶段接收事件。一旦在捕获阶段收到它,就必须阻止事件传播到DOM树中较低元素的任何事件处理程序,或者已经注册为在冒泡阶段监听的事件(即元素/阶段上的所有侦听器在听众之后参加活动)。您可以致电event.stopPropagation()

    在捕获阶段接收事件

    使用addEventListener(type, listener[, useCapture])添加监听器时,您可以将click参数设为useCapture

    引用MDN:

      

    [true是]一个布尔值,表示在将这种类型的事件调度到DOM树下面的任何EventTarget 之前,它将被调度到已注册的侦听器。向上冒泡到树中的事件不会触发指定使用捕获的侦听器。当两个元素都已为该事件注册了句柄时,事件冒泡和捕获是传播嵌套在另一个元素中的元素中发生的事件的两种方式。事件传播模式确定元素接收事件的顺序。有关详细说明,请参阅DOM Level 3事件和JavaScript事件顺序。如果未指定,useCapture默认为false。

    阻止其他处理程序获取事件

    • event.preventDefault()用于阻止默认操作(例如,阻止浏览器在useCapture上导航到href的{​​{1}}。 [这在下面的示例中使用,但没有实际效果,因为文本没有默认操作。它在这里使用是因为大多数情况下,当您添加单击事件处理程序时,您希望阻止默认操作。因此,养成这样做的习惯是个好主意,当你知道自己不想这样做时就不这样做。]
    • event.stopPropagation()用于防止任何事件阶段中的元素上的任何处理程序接收事件。它不会阻止调用当前元素和阶段上的任何其他处理程序。它不会阻止发生默认操作。
    • event.stopImmediatePropagation():相同元素和阶段的处理程序按添加顺序调用。除了与<a>具有相同的效果之外,click还会阻止同一元素和事件阶段上的任何其他处理程序接收事件。它不会阻止发生默认操作。鉴于这个问题的要求是防止事件传播给孩子,我们不需要使用它,但可以这样做,而不是使用event.stopPropagation()。但请注意,同一元素上的侦听器按其添加顺序调用。因此,event.stopImmediatePropagation()不会阻止那些听众在与听众相同的元素和阶段接收事件,而这些听众是在听众之前添加的。

    实施例

    在以下示例中,事件侦听器放置在父元素event.stopPropagation()元素上。只有放在父级上的侦听器才会收到该事件,因为它在子级之前的捕获阶段接收到该事件并且执行event.stopImmediatePropagation()

    <div>
    event.stopPropagation()

    的jQuery

    jQuery不支持在事件上使用捕获。有关原因的详细信息,请参阅:“Why does jQuery event model does not support event Capture and just supports event bubbling

答案 1 :(得分:11)

如果您知道没有任何子元素是交互式的,在某些情况下可能会有用的另一个选项是在您的css(link)中设置pointer-events: none。我通常将它应用于我想要捕获交互的元素的所有子元素。像这样:

#parentDiv * {
    pointer-events: none
}

请注意*,声明该规则适用于parentDiv的所有子女。

答案 2 :(得分:2)

  • 防止children收到家长的点击事件:
parent.addEventListener('click',function(e){
  e.stopPropagation();
  console.log('event on parent!')
},true);

(请注意,第二个参数是true

  • 防止parent收到其本身或孩子的点击事件:
parent.addEventListener('click',function(e){
  e.stopPropagation();
  console.log('event on parent or childs!', e.target.closest('.parent_selector'))
});
  • e.stopPropagation意味着停止层次结构中的下一个接收事件。
  • 第二个参数(useCapture)是一个标志,表示颠倒接收事件的顺序。 (使用capture阶段而不是bubble阶段。) 这意味着如果将其设置为true,则父级将收到click事件,然后是子级。 (通常,孩子会首先获得该活动。)

(有关详细说明,请参见@Makyen的答案。)

答案 3 :(得分:0)

为了让生活变得简单而轻松,我在这里
在类似于此

的父节点上使用
target_image.addEventListener('drop',dropimage,true);


这将启用父子祖先关系,并且将为父子调用同一事件。
要使事件仅为父事件调用,请在事件处理程序中使用以下代码段。第一行

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

答案 4 :(得分:-1)

您可以在元素上使用CustomEvents属性。

  • 创建一个事件对象,让子元素将事件调度到其父

见这里的演示

document.getElementById('parent').onclick = function() {
  alert("you are clicking on the parent stop it");
}
document.getElementById('child').onclick = function(e) {
  alert('I am sending this event to my parent');
  event = new CustomEvent('click');
  document.getElementById('parent').dispatchEvent(event);

}
#parent {
  display: inline-block;
  width: 100px;
  height: 100px;
  border: solid black;
}

#child {
  border: solid red;
}
<div id=parent>
  <div id=child>I am a child</div>
</div>

答案 5 :(得分:-3)

如果您要防止触发已创建的点击事件

$('#child').off('click',childEvent);

这样,当单击子级时,父级事件将触发,但子级事件将不触发。如果您想稍后启用子事件

$('#child').on('click',childEvent);

PS:

var childEvent = function(e) { ... }