子元素和父元素都可以被点击(子元素可能是带有jQuery点击事件的链接或div)。当我点击子元素时,如何仅触发父元素的点击事件而不触发子元素的事件?
子元素和父元素都可以被点击(子元素可能是带有jQuery点击事件的链接或div)。当我点击子元素时,如何仅触发父元素的点击事件而不触发子元素的事件?
事件有三个阶段:
<window>
开始,依次向下通过后代元素,直到事件的目标元素。事件还有一个“默认行为”,它发生在冒泡阶段之后。默认行为是浏览器针对特定类型事件在目标元素上执行的预定义操作(例如,在单击 <a>
元素上的 click
事件时,浏览器会导航至链接的 href
,而在其他类型元素上点击可能会有不同的默认行为)。
DOM Level 3 Events draft中有一张图表,用图形化的方式展示了事件如何在DOM中传播:
版权所有 © 2016 万维网联盟, (麻省理工学院, 欧洲研究中心协会, 慶應義塾大学, 北京航空航天大学). http://www.w3.org/Consortium/Legal/2015/doc-license (根据许可证允许使用)
如果想了解有关事件捕获和冒泡的更多信息,请参见: "什么是事件冒泡和捕获?"; DOM Level 3 Events draft; 或W3C DOM4: Events
如果您想在子元素上发生事件之前在父元素上接收并阻止事件,您需要在捕获阶段接收事件。一旦您在捕获阶段接收到它,就必须阻止事件传播到DOM树中较低的任何元素上的任何事件处理程序,或者已注册以在冒泡阶段侦听的元素/阶段上的所有侦听器(即在您的侦听器之后访问事件的所有侦听器)。您可以通过调用event.stopPropagation()
来实现此目的。
addEventListener(type, listener[, useCapture])
添加监听器时,您可以将 useCapture
参数设置为 true
。[
useCapture
] 是一个布尔值,指示在事件被分派到 DOM 树中的任何 EventTarget 之前,将该类型的事件分派给注册的侦听器。向上冒泡的事件不会触发指定使用捕获的侦听器。事件冒泡和捕获是传播在嵌套在另一个元素中的元素中发生的事件的两种方式,当这两个元素都为该事件注册了处理程序时。事件传播模式确定元素接收事件的顺序。有关详细说明,请参阅 DOM Level 3 Events 和 JavaScript Event order。如果未指定,则useCapture
默认为 false。
event.preventDefault()
用于阻止默认操作(例如防止浏览器在单击时导航到<a>
的href
)。[在下面的示例中使用了它,但实际上没有任何效果,因为文本没有默认操作。这里使用它是因为大多数情况下,当您添加单击事件处理程序时,您希望阻止默认操作。因此,养成这样的习惯是一个好主意,只有在您知道不想这么做时才不这样做。]event.stopPropagation()
用于防止后续事件阶段中元素上的任何处理程序接收事件。它不会防止当前元素和阶段上的任何其他处理程序被调用。它不会防止默认操作发生。event.stopImmediatePropagation()
:同一元素和阶段上的处理程序按添加顺序调用。除具有与event.stopPropagation()
相同的效果外,event.stopImmediatePropagation()
还会防止同一元素和事件阶段上的任何其他处理程序接收事件。它不会防止默认操作发生。考虑到此问题的要求是防止事件传播到子级,我们不需要使用它,但可以使用它代替event.stopPropagation()
。但请注意,同一元素上的侦听器按添加顺序调用。因此,event.stopImmediatePropagation()
不会防止那些在您的侦听器之前添加到相同元素和阶段上的侦听器接收事件。在下面的例子中,事件监听器被放置在父元素和子元素的<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 事件模型不支持事件捕获,只支持事件冒泡"
element['onclick'] = function(e) {};
? - Cagatay Ulubay在某些情况下,如果您知道没有子元素是交互式的,则可以在CSS中设置pointer-events:none
,这对于此选项可能会有用(link)。我通常将其应用于我想捕获交互的元素的所有子元素。像这样:
#parentDiv * {
pointer-events: none
}
*
,表示该规则适用于parentDiv
的所有子元素。pointer-events
。 - Makyenchildren
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 的回答。)
(click)="openAttendeesList(event.id,event.eventDetailId,event.eventDate) ; $event.stopPropagation();"
为了让生活变得更加简单和容易,我在这里
使用类似于此的父节点
target_image.addEventListener('drop',dropimage,true);
event.stopPropagation();
event.preventDefault();
您可以在元素上使用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>
element.onclick
属性是一个坏主意。分配给该属性会替换已经定义的任何侦听器(只能在属性/属性上存在一个)。这可能会导致您无法完全控制的页面出现故障。在JavaScript中,更好的方法是使用addEventListener()
。 - Makyen
showdev
提到的那样包含更多信息,因为没有具体的示例,很难看出这个功能如何运作。 - Dan Sabin