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);
}
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);
5 回答
Description:
quirksmode.org对此有一个很好的描述 . 简而言之(从quirksmode复制):
element1的事件处理程序首先触发,element2的事件处理程序最后触发 . 事件冒泡当您使用事件冒泡/
--------------- | | -----------------
| element1 | | |
| ----------- | | -----------
| | element2 | | | |
| ------------------------- |
|活动BUBBLING |
element2的事件处理程序首先触发,element1的事件处理程序最后触发 .
What to use?
这取决于你想做什么 . 没有更好的 . 不同之处在于事件处理程序的执行顺序 . 大多数情况下,在冒泡阶段发射事件处理程序是很好的,但也可能需要提前解雇它们 .
还有Event.eventPhase属性可以告诉您事件是在目标还是来自其他地方 .
请注意,尚未确定浏览器兼容性 . 我在Chrome(66.0.3359.181)和Firefox(59.0.3)上进行了测试,并在那里支持 .
扩展已经great snippet from the accepted answer,这是使用
eventPhase
属性的输出如果有两个元素元素1和元素2.元素2在元素1内部,我们附加一个事件处理程序,两个元素让我们说onClick . 现在当我们点击元素2时,将执行两个元素的eventHandler . 现在问题在于事件将以何种顺序执行 . 如果首先执行附加了元素1的事件,则称之为事件捕获,如果首先执行附加元素2的事件,则称为事件冒泡 . 根据W3C,事件将在捕获阶段开始,直到它到达目标回到元素然后它开始冒泡
捕获和冒泡状态由addEventListener方法的useCapture参数已知
默认情况下,useCapture为false . 这意味着它处于冒泡阶段 .
请尝试改变真假 .
事件冒泡和捕获是HTML DOM API中事件传播的两种方式,当事件发生在另一个元素内的元素中时,两个元素都已为该事件注册了句柄 . 事件传播模式在which order the elements receive the event中确定 .
通过冒泡,事件首先被最内层元素捕获和处理,然后传播到外部元素 .
通过捕获,事件首先由最外层元素捕获并传播到内部元素 .
捕获也称为“滴流”,这有助于记住传播顺序:
在过去,Netscape主张事件捕获,而微软则推动事件冒泡 . 两者都是W3C Document Object Model Events标准(2000)的一部分 .
IE <9使用only event bubbling,而IE9和所有主流浏览器都支持两者 . 另一方面,performance of event bubbling may be slightly lower用于复杂的DOM .
我们可以使用
addEventListener(type, listener, useCapture)
在冒泡(默认)或捕获模式下注册事件处理程序 . 要使用捕获模型,请将第三个参数传递为true
.示例
在上面的结构中,假设
li
元素中发生了单击事件 .在捕获模型中,事件将首先由
div
处理(div
中的单击事件处理程序将首先触发),然后在ul
中,然后在目标元素中的最后一个li
处理 .在冒泡模型中,会发生相反的情况:事件将首先由
li
处理,然后由ul
处理,最后由div
元素处理 .有关更多信息,请参阅
在QuirksMode上
在MDN上
在QuirksMode上
在下面的示例中,如果单击任何突出显示的元素,您可以看到事件传播流的捕获阶段首先发生,然后是冒泡阶段 .
Another example at JSFiddle .
我发现这个tutorial at javascript.info在解释这个主题时非常清楚 . 最后的三点总结实际上是在谈论关键点 . 我在这里引用它: