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

子和父都可以点击(子可以是jQuery点击事件的链接或div)。 当我点击孩子时,我怎么只触发父点击事件而不是子事件?

DOM事件阶段

活动分为三个阶段:

  1. 捕获:第一阶段是“捕获”,其中从开始调用事件处理程序,并通过后代向下移动到事件的目标。
  2. 目标:当调用目标上的事件侦听器时,第二阶段是“目标”阶段。
  3. 冒泡:第三阶段是“冒泡”,它开始于首先调用目标父节点的处理程序,然后逐步调用该元素的祖先。

事件还有一个“默认动作”,它发生在冒泡阶段之后。 默认操作是浏览器定义的操作,通常对于作为事件目标的元素类型的指定类型的事件发生(例如,浏览器在click时导航到href ,而click在另一种类型的元素上将有不同的默认操作)。

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

使用DOM事件流在DOM树中调度的事件的图形表示
图像版权所有©2016 万维网联盟 ,( 麻省理工学院 , ERCIM , 京王 , 北京 )。 http://www.w3.org/Consortium/Legal/2015/doc-license ( 根据许可证允许使用 )

有关捕获和冒泡的更多信息,请参阅:“ 什么是事件冒泡和捕获? ”; DOM Level 3 Events草案 ; 或者W3C DOM4:事件

防止事件发生在孩子身上

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

在捕获阶段接收事件

使用addEventListener(type, listener[, useCapture])添加侦听器时,可以将useCapture参数设置为true

引用MDN:

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

阻止其他处理程序获得此事件

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

在以下示例中,事件侦听器放置在父元素和子

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

 var parent=document.getElementById('parent'); var child=document.getElementById('child'); var preventChild=document.getElementById('preventChild'); parent.addEventListener('click',function(event){ if(preventChild.checked) { event.stopPropagation(); } event.preventDefault(); var targetText; if(event.target === parent) { targetText='parent'; } if(event.target === child) { targetText='child'; } console.log('Click Detected in parent on ' + targetText); },true); child.addEventListener('click',function(event){ console.log('Click Detected in child (bubbling phase)'); }); child.addEventListener('click',function(event){ console.log('Click Detected in child (capture phase)'); },true); 
 Prevent child from getting event 
Parent Text
Child Text

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

 #parentDiv * { pointer-events: none } 

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

您可以在元素上使用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; } 
 
I am a child

如果要阻止触发已创建的单击事件

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

这样,单击子项时将触发父事件,但子事件不会触发。 如果要稍后启用子事件

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

PS:

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