Javascript 如何仅在单击子项时触发父级单击事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38861601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to ONLY trigger parent click event when a child is clicked
提问by Mike Li
Both child and parent are clickable (child could be a link or div with jQuery click events). When I click on child, how do I only trigger parent click event but not the child event?
child 和 parent 都是可点击的(child 可以是带有 jQuery click 事件的链接或 div)。当我点击孩子时,如何只触发父点击事件而不触发子事件?
回答by Makyen
DOM Event Phases
DOM 事件阶段
Events have three phases:
活动分为三个阶段:
- Capture:The first phase is "capture" where event handlers are called starting with the
<window>
and moving down through descendants towards the target of the event. - Target:The second phase is the "target" phase when the event listeners on the target are called.
- Bubbling:The third phase is "bubbling" which starts with the handlers listening on parent of the target being called first, then, progressively, the ancestors of that element.
- 捕获:第一阶段是“捕获”,在此阶段调用事件处理程序,从 开始
<window>
并向下移动到事件目标的后代。 - 目标:第二阶段是调用目标上的事件侦听器时的“目标”阶段。
- 冒泡:第三个阶段是“冒泡”,首先监听目标的父级的处理程序首先被调用,然后逐步调用该元素的祖先。
Events also have a "default action", which happens after the bubbling phase. The default action is the browser-defined action that normally occurs for events of the specified type on the kind of element which is the target of the event (e.g. the browser navigating to the href
of an <a>
upon a click
, whereas a click
on another type of element will have a different default action).
事件也有一个“默认动作”,它发生在冒泡阶段之后。默认动作是通常发生为是事件的目标的种类元素的指定类型的事件(浏览器定义的动作例如在浏览器导航到href
的<a>
在一个click
,而click
在另一种类型的元件的意志有不同的默认操作)。
The DOM Level 3 Events drafthas a diagram that graphically shows how events propagate through the DOM:
在DOM级别3事件草案有一个图,以图形方式显示事件通过DOM如何传播:
Image Copyright ? 2016 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang). http://www.w3.org/Consortium/Legal/2015/doc-license(Use permitted per the license)
图片版权?2016万维网联盟,(MIT、ERCIM、Keio、北航)。http://www.w3.org/Consortium/Legal/2015/doc-license(许可证允许使用)
For more information, on capture and bubbling, see: "What is event bubbling and capturing?"; The DOM Level 3 Events draft; or W3C DOM4: Events
有关捕获和冒泡的更多信息,请参阅:“什么是事件冒泡和捕获?”;在DOM Level 3的草稿活动; 或W3C DOM4:事件
Preventing the event from getting to the child
防止事件影响孩子
For what you want, to get the event on the parent prior to, and prevent, the event on the child, you have to receive the event in the capture phase. Once you have received it in the capture phase, you have to stop the event from propagating to any event handlers on elements lower in the DOM tree, or which have registered to listen in the bubbling phase (i.e. all listeners on elements/phases which would be visited by the event after your listener). You do this by calling event.stopPropagation()
.
对于您想要的,要在父事件之前获取事件并阻止子事件发生,您必须在捕获阶段接收事件。一旦你在捕获阶段收到它,你必须阻止事件传播到 DOM 树中较低元素上的任何事件处理程序,或者在冒泡阶段注册侦听的元素(即元素/阶段上的所有侦听器)在您的听众之后被事件访问)。您可以通过调用event.stopPropagation()
.
Receiving events during the capture phase
在捕获阶段接收事件
When adding the listener with addEventListener(type, listener[, useCapture])
, you can have the useCapture
argument be true
.
添加带有 的侦听器时addEventListener(type, listener[, useCapture])
,您可以将useCapture
参数设为true
。
Quoting MDN:
引用 MDN:
[
useCapture
is] A Boolean that indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. Events that are bubbling upward through the tree will not trigger a listener designated to use capture. Event bubbling and capturing are two ways of propagating events that occur in an element that is nested within another element, when both elements have registered a handle for that event. The event propagation mode determines the order in which elements receive the event. See DOM Level 3 Events and JavaScript Event order for a detailed explanation. If not specified,useCapture
defaults to false.
[
useCapture
is] 一个布尔值,表示这种类型的事件将被分派到注册的侦听器,然后再分派到 DOM 树中它下面的任何 EventTarget。通过树向上冒泡的事件不会触发指定使用捕获的侦听器。事件冒泡和捕获是传播发生在嵌套在另一个元素中的元素中的事件的两种方式,当两个元素都为该事件注册了句柄时。事件传播模式决定了元素接收事件的顺序。有关详细说明,请参阅 DOM 级别 3 事件和 JavaScript 事件顺序。如果未指定,则useCapture
默认为 false。
Preventing other handlers getting the event
防止其他处理程序获取事件
event.preventDefault()
is used to prevent the default action (e.g. prevent the browser from navigating to thehref
of an<a>
upon aclick
). [This is used in the example below, but has no real effect as there is no default action for text. It's used here because most of the time when you are adding a click event handler you want to prevent the default action. Thus, it's a good idea to be in the habit of doing so, and just not doing so when you know you don't want to.]event.stopPropagation()
is used to prevent any handlers on elements later in any of the event phases from receiving the event. It does not prevent any additional handlers on the current element and phasefrom being called. It does not prevent the default action from occurring.event.stopImmediatePropagation()
: Handlers on the same element and phase are called in the order in which they are added. In addition to having the same effect asevent.stopPropagation()
,event.stopImmediatePropagation()
prevents any additional handlers on the same element and event phasefrom receiving the event. It does not prevent the default action from occurring. Given that the requirement for this question is to prevent the event from propagating to children, we don't need to use this, but could do so instead of usingevent.stopPropagation()
. Note, however, that listeners on the same element are called in the order they are added. Thus,event.stopImmediatePropagation()
will not prevent the event from being received by those listeners on the same element and phase as your listener which were added prior to your listener.
event.preventDefault()
用于防止默认动作(例如防止浏览器导航到href
的<a>
在一个click
)。[这在下面的示例中使用,但没有实际效果,因为文本没有默认操作。在这里使用它是因为在大多数情况下,当您添加单击事件处理程序时,您希望阻止默认操作。因此,养成这样做的习惯是个好主意,只是在您知道不想这样做时才这样做。]event.stopPropagation()
用于防止稍后在任何事件阶段中元素上的任何处理程序接收事件。它不会阻止调用当前元素和阶段上的任何其他处理程序。它不会阻止默认操作的发生。event.stopImmediatePropagation()
: 相同元素和阶段上的处理程序按添加顺序调用。除了与 具有相同的效果之外event.stopPropagation()
,还event.stopImmediatePropagation()
可以防止同一元素和事件阶段上的任何其他处理程序接收事件。它不会阻止默认操作的发生。鉴于此问题的要求是防止事件传播给孩子,我们不需要使用 this,但可以这样做而不是使用event.stopPropagation()
. 但是请注意,同一元素上的侦听器是按添加顺序调用的。因此,event.stopImmediatePropagation()
不会阻止在与您的侦听器相同的元素和阶段上的那些侦听器接收事件,这些侦听器是在您的侦听器之前添加的。
Example
例子
In the following example, event listeners are placed on both the parent and the child <div>
elements. Only the listener placed on the parent receives the event because it receives the event during the capture phase prior to the child and it executes event.stopPropagation()
.
在以下示例中,事件侦听器放置在父<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 does not support using capture on events. For more information as to why see: "Why does jQuery event model does not support event Capture and just supports event bubbling"
jQuery 不支持对事件使用捕获。有关原因的更多信息,请参阅:“为什么 jQuery 事件模型不支持事件捕获而只支持事件冒泡”
回答by Abraham Brookes
Another option for this that may be useful in certain circumstances when you know that none of the child elements are interactive is to set pointer-events: none
in your css (link). I usually apply it to all child elements of the element on which I want to capture interaction. Like this:
当您知道没有任何子元素是交互式的时,在某些情况下可能有用的另一个选项是pointer-events: none
在您的 css ( link) 中设置。我通常将它应用于我想要捕获交互的元素的所有子元素。像这样:
#parentDiv * {
pointer-events: none
}
Note the *
, declaring that the rule applies to all children of the parentDiv
.
请注意*
,声明该规则适用于 的所有子项parentDiv
。
回答by Vinod Kumar
To make life really simple and easy here i am
Use on parent node similar to this
为了让生活变得非常简单和轻松,我在
与此类似的父节点上使用
target_image.addEventListener('drop',dropimage,true);
This will enable the parent child ancestor relationship and the same event will be called in for the parent and child.
To make the event only be called for the parent use the following code snippet in the event handler. First line
这将启用父子祖先关系,并且将为父子关系调用相同的事件。
要使事件只为父级调用,请在事件处理程序中使用以下代码片段。第一行
event.stopPropagation();
event.preventDefault();
回答by repzero
You can use the CustomEvents property on elements.
您可以在元素上使用 CustomEvents 属性。
- Create an event object and let the child element dispatch the event to its parent
- 创建一个事件对象,让子元素将事件分派给它的父元素
see demo here
在这里看演示
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>