Javascript 什么是事件冒泡和捕获?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4616694/
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
What is event bubbling and capturing?
提问by Arun P Johny
What is the difference between event bubbling and capturing? When should one use bubbling vs capturing?
事件冒泡和捕获有什么区别?什么时候应该使用冒泡和捕获?
回答by Arun P Johny
Event bubbling and capturing are two ways of event propagation in the HTML DOM API, when an event occurs in an element inside another element, and both elements have registered a handle for that event. The event propagation mode determines in which order the elements receive the event.
事件冒泡和捕获是 HTML DOM API 中事件传播的两种方式,当一个事件发生在另一个元素内的元素中,并且两个元素都为该事件注册了一个句柄时。事件传播模式决定了元素接收事件的顺序。
With bubbling, the event is first captured and handled by the innermost element and then propagated to outer elements.
使用冒泡,事件首先被最里面的元素捕获和处理,然后传播到外部元素。
With capturing, the event is first captured by the outermost element and propagated to the inner elements.
使用捕获,事件首先被最外层元素捕获并传播到内部元素。
Capturing is also called "trickling", which helps remember the propagation order:
捕获也称为“涓流”,它有助于记住传播顺序:
trickle down, bubble up
涓涓细流,冒泡
Back in the old days, Netscape advocated event capturing, while Microsoft promoted event bubbling. Both are part of the W3C Document Object Model Eventsstandard (2000).
过去,Netscape 提倡事件捕获,而 Microsoft 则提倡事件冒泡。两者都是 W3C文档对象模型事件标准 (2000) 的一部分。
IE < 9 uses only event bubbling, whereas IE9+ and all major browsers support both. On the other hand, the performance of event bubbling may be slightly lowerfor complex DOMs.
IE < 9只使用事件冒泡,而 IE9+ 和所有主流浏览器都支持。另一方面,对于复杂的 DOM ,事件冒泡的性能可能会稍低一些。
We can use the addEventListener(type, listener, useCapture)
to register event handlers for in either bubbling (default) or capturing mode. To use the capturing model pass the third argument as true
.
我们可以addEventListener(type, listener, useCapture)
在冒泡(默认)或捕获模式下使用来注册事件处理程序。要使用捕获模型,将第三个参数作为true
.
Example
例子
<div>
<ul>
<li></li>
</ul>
</div>
In the structure above, assume that a click event occurred in the li
element.
在上面的结构中,假设li
元素中发生了点击事件。
In capturing model, the event will be handled by the div
first (click event handlers in the div
will fire first), then in the ul
, then at the last in the target element, li
.
在捕获模型中,事件将由div
第一个处理(将首先div
触发中的单击事件处理程序),然后是ul
,然后是目标元素中的最后一个li
。
In the bubbling model, the opposite will happen: the event will be first handled by the li
, then by the ul
, and at last by the div
element.
在冒泡模型中,会发生相反的情况:事件将首先由 处理li
,然后由处理ul
,最后由div
元素处理。
For more information, see
有关更多信息,请参阅
- Event Orderon QuirksMode
- addEventListeneron MDN
- Events Advancedon QuirksMode
- QuirksMode 上的事件顺序
- 的addEventListener上MDN
- QuirksMode 上的高级事件
In the example below, if you click on any of the highlighted elements, you can see that the capturing phase of the event propagation flow occurs first, followed by the bubbling phase.
在下面的示例中,如果您单击任何突出显示的元素,您可以看到事件传播流的捕获阶段首先发生,然后是冒泡阶段。
var logElement = document.getElementById('log');
function log(msg) {
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function capture() {
log('capture: ' + this.firstChild.nodeValue.trim());
}
function bubble() {
log('bubble: ' + this.firstChild.nodeValue.trim());
}
function clearOutput() {
logElement.innerHTML = "";
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>
回答by Felix Kling
Description:
描述:
quirksmode.orghas a nice description of this. In a nutshell (copied from quirksmode):
quirksmode.org对此有很好的描述。简而言之(从 quirksmode 复制):
Event capturing
When you use event capturing
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
the event handler of element1 fires first, the event handler of element2 fires last.
Event bubbling
When you use event bubbling
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
the event handler of element2 fires first, the event handler of element1 fires last.
事件捕捉
使用事件捕获时
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
element1 的事件处理程序首先触发,element2 的事件处理程序最后触发。
事件冒泡
当你使用事件冒泡时
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
element2 的事件处理程序首先触发,element1 的事件处理程序最后触发。
What to use?
用什么?
It depends on what you want to do. There is no better. The difference is the order of the execution of the event handlers. Most of the time it will be fine to fire event handlers in the bubblingphase but it can also be necessary to fire them earlier.
这取决于你想做什么。没有更好的了。不同之处在于事件处理程序的执行顺序。大多数情况下,在冒泡阶段触发事件处理程序是没问题的,但也可能需要更早地触发它们。
回答by dinesh_malhotra
If there are two elements element 1 and element 2. Element 2 is inside element 1 and we attach an event handler with both the elements lets say onClick. Now when we click on element 2 then eventHandler for both the elements will be executed. Now here the question is in which order the event will execute. If the event attached with element 1 executes first it is called event capturing and if the event attached with element 2 executes first this is called event bubbling. As per W3C the event will start in the capturing phase until it reaches the target comes back to the element and then it starts bubbling
如果有两个元素,元素 1 和元素 2。元素 2 位于元素 1 内,我们为这两个元素附加一个事件处理程序,比如说 onClick。现在,当我们单击元素 2 时,将执行这两个元素的 eventHandler。现在的问题是事件将按什么顺序执行。如果与元素 1 相关联的事件首先执行,则称为事件捕获,如果与元素 2 相关联的事件首先执行,则称为事件冒泡。根据 W3C,事件将在捕获阶段开始,直到到达目标返回元素,然后开始冒泡
The capturing and bubbling states are known by the useCapture parameter of addEventListener method
捕获和冒泡状态由 addEventListener 方法的 useCapture 参数知道
eventTarget.addEventListener(type,listener,[,useCapture]);
eventTarget.addEventListener(type,listener,[,useCapture]);
By Default useCapture is false. It means it is in the bubbling phase.
默认情况下 useCapture 为 false。这意味着它处于冒泡阶段。
var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");
div1.addEventListener("click", function (event) {
alert("you clicked on div 1");
}, true);
div2.addEventListener("click", function (event) {
alert("you clicked on div 2");
}, false);
#div1{
background-color:red;
padding: 24px;
}
#div2{
background-color:green;
}
<div id="div1">
div 1
<div id="div2">
div 2
</div>
</div>
Please try with changing true and false.
请尝试更改真假。
回答by gm2008
I have found this tutorial at javascript.infoto be very clear in explaining this topic. And its 3-points summary at the end is really talking to the crucial points. I quote it here:
我发现javascript.info上的这个教程非常清楚地解释了这个主题。而它最后的三点总结,真的是说到要害了。我在这里引用:
- Events first are captured down to deepest target, then bubble up. In IE<9 they only bubble.
- All handlers work on bubbling stage excepts
addEventListener
with last argumenttrue
, which is the only way to catch the event on capturing stage.- Bubbling/capturing can be stopped by
event.cancelBubble=true
(IE) orevent.stopPropagation()
for other browsers.
- 事件首先被捕获到最深的目标,然后冒泡。在 IE<9 中,它们只会冒泡。
- 除了
addEventListener
最后一个参数外true
,所有处理程序都在冒泡阶段工作 ,这是在捕获阶段捕获事件的唯一方法。event.cancelBubble=true
(IE) 或event.stopPropagation()
其他浏览器可以停止冒泡/捕获。
回答by Adelin
There's also the Event.eventPhase
property which can tell you if the event is at target or comes from somewhere else.
还有一个Event.eventPhase
属性可以告诉你事件是在目标还是来自其他地方。
Note that the browser compatibility is not determined yet. I tested it on Chrome (66.0.3359.181) and Firefox (59.0.3) and it is supported there.
请注意,浏览器兼容性尚未确定。我在 Chrome (66.0.3359.181) 和 Firefox (59.0.3) 上对其进行了测试,并且在那里受支持。
Expanding on the already great snippet from the accepted answer, this is the output using the eventPhase
property
从接受的答案中扩展已经很棒的片段,这是使用eventPhase
属性的输出
var logElement = document.getElementById('log');
function log(msg) {
if (logElement.innerHTML == "<p>No logs</p>")
logElement.innerHTML = "";
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function humanizeEvent(eventPhase){
switch(eventPhase){
case 1: //Event.CAPTURING_PHASE
return "Event is being propagated through the target's ancestor objects";
case 2: //Event.AT_TARGET
return "The event has arrived at the event's target";
case 3: //Event.BUBBLING_PHASE
return "The event is propagating back up through the target's ancestors in reverse order";
}
}
function capture(e) {
log('capture: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
function bubble(e) {
log('bubble: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>
回答by Kondal
Bubbling
冒泡
Event propagate to the upto root element is **BUBBLING**.
Capturing
捕捉
Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.