繁体   English   中英

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

[英]How to ONLY trigger parent click event when a child is clicked

子项和父项都是可点击的(子项可以是具有 jQuery 单击事件的链接或 div)。 当我点击子项时,如何只触发父级点击事件而不触发子级事件?

DOM 事件阶段

活动分为三个阶段:

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

事件也有一个“默认动作”,它发生在冒泡阶段之后。 默认操作是浏览器定义的操作,通常发生在作为事件目标的元素种类上的指定类型的事件(例如,浏览器在click时导航到<a>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 is] 一个布尔值,指示这种类型的事件将被分派到注册的侦听器,然后再分派到 DOM 树中它下面的任何 EventTarget 通过树向上冒泡的事件不会触发指定使用捕获的侦听器。 事件冒泡和捕获是传播发生在嵌套在另一个元素中的元素中的事件的两种方式,当两个元素都为该事件注册了句柄时。 事件传播模式决定了元素接收事件的顺序。 有关详细说明,请参阅 DOM 级别 3 事件和 JavaScript 事件顺序。 如果未指定,则useCapture默认为 false。

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

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

示例

在以下示例中,事件侦听器放置在父<div>元素和子<div>元素上。 只有放置在父级上的侦听器接收事件,因为它在子级之前的捕获阶段接收事件并执行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);
 <input id="preventChild" type="checkbox" checked>Prevent child from getting event</input> <div id="parent">Parent Text<br/> <div id="child" style="margin-left:10px;">Child Text<br/> </div> </div>

jQuery

jQuery 不支持对事件使用捕获。 有关原因的更多信息,请参阅:“ 为什么 jQuery 事件模型不支持事件捕获而只支持事件冒泡

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

#parentDiv * {
    pointer-events: none
}

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

  • 防止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,则父级将收到单击事件,然后是子级。 (通常孩子会先得到事件。)

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

为了让生活变得非常简单和轻松,我在这里
在与此类似的父节点上使用

target_image.addEventListener('drop',dropimage,true);


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

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

您可以在 html 文件中使用 $event.stopPropagation() 。

(click)="openAttendeesList(event.id,event.eventDetailId,event.eventDate); $event.stopPropagation();"

您可以在元素上使用 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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM