事件冒泡和捕获之间的区别是什么?什么时候应该使用冒泡和捕获?
当前回答
正如其他人所说,冒泡和捕获描述了一些嵌套元素接收给定事件的顺序。
我想指出,对于最里面的元素可能会出现一些奇怪的东西。实际上,在这种情况下,添加事件侦听器的顺序确实很重要。
在下面的例子中,捕获div2将先执行,然后再执行冒泡;当为div4冒泡时,将先执行而不是捕获。
function addClickListener (msg, num, type) { document.querySelector("#div" + num) .addEventListener("click", () => alert(msg + num), type); } bubble = (num) => addClickListener("bubble ", num, false); capture = (num) => addClickListener("capture ", num, true); // first capture then bubble capture(1); capture(2); bubble(2); bubble(1); // try reverse order bubble(3); bubble(4); capture(4); capture(3); #div1, #div2, #div3, #div4 { border: solid 1px; padding: 3px; margin: 3px; } <div id="div1"> div 1 <div id="div2"> div 2 </div> </div> <div id="div3"> div 3 <div id="div4"> div 4 </div> </div>
编辑:这种行为可能因浏览器而异(例如,目前在Firefox上出现,但在Chrome和Edge上没有)。然而,我认为人们应该意识到这一点。
其他回答
DOM Events描述了事件传播的3个阶段:捕获阶段——事件向下到元素。目标阶段——事件到达目标元素。冒泡阶段——事件从元素冒泡。
正如其他人所说,冒泡和捕获描述了一些嵌套元素接收给定事件的顺序。
我想指出,对于最里面的元素可能会出现一些奇怪的东西。实际上,在这种情况下,添加事件侦听器的顺序确实很重要。
在下面的例子中,捕获div2将先执行,然后再执行冒泡;当为div4冒泡时,将先执行而不是捕获。
function addClickListener (msg, num, type) { document.querySelector("#div" + num) .addEventListener("click", () => alert(msg + num), type); } bubble = (num) => addClickListener("bubble ", num, false); capture = (num) => addClickListener("capture ", num, true); // first capture then bubble capture(1); capture(2); bubble(2); bubble(1); // try reverse order bubble(3); bubble(4); capture(4); capture(3); #div1, #div2, #div3, #div4 { border: solid 1px; padding: 3px; margin: 3px; } <div id="div1"> div 1 <div id="div2"> div 2 </div> </div> <div id="div3"> div 3 <div id="div4"> div 4 </div> </div>
编辑:这种行为可能因浏览器而异(例如,目前在Firefox上出现,但在Chrome和Edge上没有)。然而,我认为人们应该意识到这一点。
我发现这个教程在javascript.info中非常清楚地解释了这个主题。它最后的3点总结是对关键点的讨论。我在这里引用:
事件首先被捕捉到最深的目标,然后向上冒泡。在 IE<9,它们只是冒泡。 所有处理程序都在冒泡阶段上工作,除了 addEventListener的最后一个参数为真,这是唯一的方法 在捕获阶段捕获事件。 冒泡/捕获可以 由事件停止。cancelBubble=true (IE)或event.stopPropagation() 对于其他浏览器。
还有一个事件。eventPhase属性,它可以告诉你事件是在目标还是来自其他地方,浏览器完全支持。
从已接受的答案扩展已经很好的代码片段,这是使用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>
描述:
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.
用什么?
这取决于你想做什么。没有更好的了。不同之处在于事件处理程序的执行顺序。大多数情况下,在冒泡阶段触发事件处理程序是可以的,但也有必要在更早的时候触发它们。