這個問題的整理是基于面試題:
給同一個DOM元素綁定兩個事件,一個用冒泡,一個用捕獲,會執行幾次?先執行冒泡還是先執行捕獲?
例子:
<div id="outer">
<p id="inner">Click me!</p>
</div>
事件冒泡:
微軟提出了名為事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻為把一顆石頭投入水中,泡泡會一直從水底冒出水面。也就是說,事件會從最內層的元素開始發生,一直向上傳播,直到document對象。
因此上面的例子在事件冒泡的概念下發生click事件的順序應該是p -> div -> body -> html -> document
事件捕獲:
網景提出另一種事件流名為事件捕獲(event capturing)。與事件冒泡相反,事件會從最外層開始發生,直到最具體的元素。
上面的例子在事件捕獲的概念下發生click事件的順序應該是document -> html -> body -> div -> p
如下代碼,有四個div嵌套元素,均綁定了click事件,addEventListener函數的第三個參數設置為false說明不為捕獲事件,即為冒泡事件。該代碼執行結果如下:
點擊one元素,輸出one;
點擊two元素,輸出two one;
點擊three元素,輸出 three two one;
點擊four元素,輸出 four three two one;
<div id='one'>
<div id='two'>
<div id='three'>
<div id='four'>
</div>
</div>
</div>
</div>
<script>
var one=document.getElementById('one');
var two=document.getElementById('two');
var three=document.getElementById('three');
var four=document.getElementById('four');
one.addEventListener('click',function(){
alert('one');
},false);
two.addEventListener('click',function(){
alert('two');
},false);
three.addEventListener('click',function(){
alert('three');
},false);
four.addEventListener('click',function(){
alert('four');
},false);
</script>
而捕獲則相反。當觸發目標元素時,會從目標元素的最頂層的祖先元素事件往下執行到目標元素為止。
將上面的代碼第三個參數均改為true,則執行結果如下:
點擊one,輸出one;
點擊two,輸出one two;
點擊three,輸出one two three;
點擊four,輸出one two three four;
很明顯執行順序是不同的。
問題解釋:
無論是冒泡事件還是捕獲事件,元素都會先執行捕獲階段
從上往下,如有捕獲事件,則執行;一直向下到目標元素后,從目標元素開始向上執行冒泡元素
如下代碼:
此時點擊four元素,four元素為目標元素,one為根元素祖先,從one開始向下判斷執行。
one為捕獲事件,輸出one;
two為冒泡事件,忽略;
three為捕獲時間,輸出three;
four為目標元素,開始向上冒泡執行,輸出four;(從此處分為兩部分理解較容易。)
three為捕獲已執行,忽略;
two為冒泡事件,輸出two;
one為捕獲已執行,忽略。
最終執行結果為:one three four two
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two');
},false);
three.addEventListener('click',function(){
alert('three');
},true);
four.addEventListener('click',function(){
alert('four');
},false);
執行次數:綁定了幾個事件便執行幾次。
如下代碼,two元素綁定了兩個不同事件,點擊two都會執行這兩個事件。而執行順序有所差異
1、如果two為目標元素,目標元素的事情按順序執行,而其他元素根據W3C的標準執行,即先捕獲后冒泡。
點擊two執行結果:one(因為是two的父元素支持捕獲事件所以先執行) two,bubble two,capture(順序執行,注意逗號不是間隔,是輸出內容。)
2、如果目標元素不是two,則two的兩個事件按先捕獲后冒泡觸發執行,也就是跟前面討論的執行過程是一樣的,只不過兩個事件都綁定在同一個DOM元素上。
點擊three執行結果:one two,capture three,capture two,bubble
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two,bubble');
},false);
two.addEventListener('click',function(){
alert('two,capture');
},true);
three.addEventListener('click',function(){
alert('three,capture');
},true);
four.addEventListener('click',function(){
alert('four,capture');
},true);