什么是事件冒泡和捕获?

事件冒泡和捕获有什么区别? 在这两个,这是更快,更好的模式使用?

事件冒泡和捕获是事件在HTML DOM API中传播的两种方式,当一个事件发生在另一个元素内部的一个元素中时,这两个元素都注册了该事件的句柄。 事件传播模式确定元素以哪种顺序接收事件 。

冒泡时,事件首先被最内层元素捕获并处理,然后传播到外层元素。

捕获时,事件首先被最外层的元素捕获并传播到内层元素。

捕获也被称为“滴漏”,这有助于记住传播顺序:

滴下来,起泡

在过去,网景主张事件捕捉,而微软则推动事件冒泡。 两者都是W3C 文档对象模型事件标准(2000)的一部分。

IE <9 只使用事件冒泡 ,而IE9 +和所有主stream浏览器都支持。 另一方面,对于复杂的DOM ,事件冒泡的性能可能会略微降低 。

我们可以使用addEventListener(type, listener, useCapture)以冒泡(默认)或捕获模式注册事件处理程序。 要使用捕捉模型,请将第三个参数作为true

 <div> <ul> <li></li> </ul> </div> 

在上面的结构中,假设li元素中发生了点击事件。

在捕获模型中,事件将首先由div处理(在div单击事件处理程序将首先触发),然后在ul ,然后在目标元素li最后处理。

在冒泡模式中,会发生相反的情况:事件将首先由li ,然后由ul ,最后由div元素处理。

有关更多信息,请参阅

  • QuirksMode上的事件顺序
  • MDN上的addEventListener
  • QuirksMode上的高级事件

在下面的示例中,如果单击任何突出显示的元素,则可以看到事件传播stream的捕获阶段首先出现,然后是冒泡阶段。

 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()); } 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> <section id="log"></section> 

描述:

quirksmode.org对此有一个很好的描述。 简而言之(从quirksmode复制):

事件捕获

当你使用事件捕获

  | | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | ----------------------------------- 

element1的事件处理程序首先触发,element2的事件处理程序最后触发。

事件冒泡

当你使用事件冒泡

  / \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | ----------------------------------- 

element2的事件处理程序首先触发,element1的事件处理程序最后触发。


使用什么?

这取决于你想要做什么。 没有更好的。 区别在于事件处理程序的执行顺序。 大多数情况下,在冒泡阶段触发事件处理程序是可以的,但也可能有必要提前触发它们。

如果有两个元素元素1和元素2.元素2是在元素1内,我们附加一个事件处理程序,两个元素让我们说onClick。 现在当我们点击元素2时,两个元素的eventHandler将被执行。 现在问题在于事件的执行顺序。 如果元素1附加的事件首先执行,则称为事件捕获,如果元素2附加的事件首先执行,则称为事件冒泡。 根据W3C,事件将在捕获阶段开始,直到它到达目标回到元素,然后开始冒泡

捕获和冒泡状态由addEventListener方法的useCapture参数所知

eventTarget.addEventListener(types,听众,[方法,useCapture]);

默认情况下,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> 

我已经在javascript.info上find了这个教程,在解释这个主题的时候非常清楚。 最后的3分总结真的是在谈论关键点。 我在这里引用它:

  1. 事件首先被捕获到最深的目标,然后冒泡。 在IE浏览器<9他们只泡。
  2. 所有的处理器都在冒泡阶段工作,除了addEventListener的最后一个参数是true之外,这是在捕获阶段捕获事件的唯一方法。
  3. 冒泡/捕获可以通过event.cancelBubble = true(IE)或event.stopPropagation()为其他浏览器停止。