JS中事件執行的整個過程稱之為事件流,分為三個階段:事件捕獲、事件目標處理函數、事件冒泡。
當某個元素觸發某個事件(如onclick),頂級對象document發出一個事件流,順着DOM的樹節點向觸發它的目標節點流去,直到到達目標元素,這個層層遞進、向下找尋目標點的過程為事件的捕獲階段,此過程中與事件相應的函數是不會被觸發的。
到達目標元素,便會執行綁定在此元素上的、與事件相應的函數,即事件目標處理函數階段。
最后,從目標元素起,再依次往頂層對象傳遞,途中如果有節點綁定了同名事件,這些事件所對應的函數會逐一被觸發,此過程便稱之為事件冒泡。
通常情況下,事件相應的函數都是在冒泡階段觸發執行的,addEventListener的第三個參數默認false,表示冒泡時執行(為true時,函數在捕獲階段便會執行)。
使用e.stopPropagation() 或 e.cancelBubble = true(IE)可以阻斷事件向當前元素的父元素冒泡。
一個小例子
<div style="background-color: red;"> <div style="background-color: green;"> <div style="background-color: yellow;"></div> </div> </div>
var div =document.querySelectorAll('div');
function fn1(){ console.log(this); } function fn2(e){ console.log(this); e.cancelBubble = true; e.stopPropagation(); } div[0].addEventListener('click',fn1,false); div[1].addEventListener('click',fn1,false); div[2].addEventListener('click',fn2,false); div[0].addEventListener('click',fn1,true); div[1].addEventListener('click',fn1,true); div[2].addEventListener('click',fn1,true);
結果為 red—>green—>yellow—>yellow—>green
(前三個結果是事件捕獲階段執行函數輸出的,在捕獲階段,從最高節點起,但凡綁定了click事件,便執行;之后進入冒泡階段,由於div[1]身上阻止了事件冒泡,因此它的父級div[0]的click不會被觸發,事件到div[1]便停止了。)
如果把阻止冒泡的行為添加在捕獲階段,如捕獲階段的div[1]身上,則只會依次輸出捕獲過程中觸發click事件時div[0]、div[1]的函數執行結果,之后的捕獲行為和冒泡行為將全部被阻斷。