子和父都可以点击(子可以是jQuery点击事件的链接或div)。当我点击child时,我该如何仅触发父点击事件而不触发子事件?
答案 0 :(得分:60)
事件有三个阶段:
<window>
开始调用,并通过后代向下移动到事件目标。事件也有一个“默认动作”,它发生在冒泡阶段之后。默认操作是浏览器定义的操作,通常对于作为事件目标的元素类型的指定类型的事件发生(例如,浏览器导航到href
的{{1}}一个<a>
,而另一种元素的click
将有不同的默认操作。)
DOM Level 3 Events draft有一个图表,以图形方式显示事件如何通过DOM传播:
图片版权所有©2016 World Wide Web Consortium,(MIT,ERCIM,Keio,Beihang)。 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不支持在事件上使用捕获。有关原因的详细信息,请参阅:“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) { ... }