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);
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);
}
9条答案
按热度按时间lmvvr0a81#
事件冒泡和捕获是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
元素处理。有关详细信息,请参见
在下面的示例中,如果您单击任何突出显示的元素,您可以看到首先发生事件传播流的捕获阶段,然后是冒泡阶段。
x一个一个一个一个x一个一个二个一个x一个一个三个一个
Another example at JSFiddle.
k97glaaz2#
说明:
quirksmode.org对此有一个很好的描述。简单地说(复制自quirksmode):
事件捕获
使用事件捕获时
元素1的事件处理程序首先触发,元素2的事件处理程序最后触发。
事件冒泡
使用事件冒泡时
元素2的事件处理程序首先触发,元素1的事件处理程序最后触发。
使用什么?
这取决于你想做什么。没有更好的方法。不同的是事件处理程序的执行顺序。大多数情况下,在 * 冒泡 * 阶段触发事件处理程序是可以的,但也有必要提前触发它们。
2eafrhcq3#
如果有两个元素元素1和元素2,元素2在元素1的内部,我们为这两个元素附加一个事件处理程序,比如onClick,现在当我们单击元素2时,这两个元素的eventHandler都将被执行,现在的问题是事件将以什么顺序执行。如果与元素1关联的事件首先执行,则称为事件捕获;如果与元素2关联的事件首先执行,则称为事件冒泡。根据W3C,事件将在捕获阶段开始,直到它到达目标并返回到元素,然后它开始冒泡
捕获和冒泡状态可通过addEventListener方法的useCapture参数获知
添加事件监听器(类型,监听器,[,useCapture]);
默认情况下,useCapture为false。这意味着它处于冒泡阶段。
请尝试更改正确和错误。
u0sqgete4#
我发现这个tutorial at javascript.info在解释这个主题时非常清晰。它在最后的3点总结确实是在谈论关键点。我在这里引用它:
1.事件首先被捕获到最深的目标,然后冒泡。在IE〈9中,它们只冒泡。
1.所有处理程序都在冒泡阶段工作,但最后一个参数为
true
的addEventListener
除外,这是在捕获阶段捕获事件的唯一方法。1.气泡/捕获可以通过
event.cancelBubble=true
(IE)或event.stopPropagation()
(对于其他浏览器)停止。piah890a5#
还有
Event.eventPhase
属性,它可以告诉你事件是在目标还是来自其他地方,浏览器完全支持它。在已有的great snippet from the accepted answer上展开,这是使用
eventPhase
属性的输出dldeef676#
DOM Events描述了事件传播的3个阶段:捕获阶段-事件向下到达元素。目标阶段-事件到达目标元素。冒泡阶段-事件从元素冒泡。
whhtz7ly7#
"冒泡"
捕捉
vptzau2j8#
正如其他人所说,冒泡和捕获描述了一些嵌套元素接收给定事件的顺序。
我想指出的是,对于最里面的元素,可能会出现一些奇怪的情况。实际上,在这种情况下,事件侦听器被添加的顺序确实很重要。
在下面的示例中,
div2
的捕获将先于冒泡执行;而对于div4
的冒泡将比捕获先执行。abithluo9#
当浏览器检测到一个事件时,它会试图找到一个事件处理程序。这个过程有3个阶段。假设我们有这些元素
1-捕获阶段
浏览器将查看刚刚被点击的元素。然后它将转到顶部父元素
body
。如果body中有任何点击句柄,浏览器将调用它。检查body元素后,它将查看第二个顶部父元素div
元素。这个过程会一直重复,直到浏览器到达最底部的按钮元素。一旦它看到按钮元素,第一阶段-捕获就结束了。大多数时候我们忽略了这个阶段。这段代码忽略了这个阶段如果你想参与这个阶段,你必须写这个
当我们需要检测目标之外的点击时,我们需要这个阶段。也许我们有一个下拉菜单或模态打开,如果用户点击模态或下拉菜单之外的任何地方,我们希望关闭它
2-目标阶段
浏览器将查看被点击的元素,该元素是
Button
,并且如果按钮具有事件处理程序,则浏览器将调用该事件处理程序。3-气泡阶段
与
Capture Phase
相反,在这个阶段中,浏览器将从直接父元素(本例中为div
元素)启动流程,然后访问body
元素。