事件冒泡
事件冒泡
一.事件流概念
流是一種生動體現。用術語說流是對輸入輸出設備的抽象。以程序的角度說,流是具有方向的數據。
事件流分事件冒泡與事件捕獲
在瀏覽器發展的過程中,開發團隊遇到了一個問題。那就是頁面中的哪一部分擁有特定的事件?
可以想象畫在一張紙上的一組同心圓,如果你把手指放在圓心上,那麽你的手指指向的其實不是一個圓,而是紙上所有的圓。放到實際頁面中就是,你點擊一個按鈕,事實上你還同時點擊了按鈕所有的父元素。
開發團隊的問題就在於,當點擊按鈕時,是按鈕最外層的父元素先收到事件並執行,還是具體元素先收到事件並執行?所以這兒引入了事件流的概念。
通俗說,事件流所描述的就是從頁面中接受事件的順序。
因為有兩種觀點,所以事件流也有兩種,分別是事件冒泡和事件捕獲。現主流是事件冒泡。
事件冒泡
事件冒泡即事件開始時,由最具體的元素接收(也就是事件發生所在的節點),然後逐級傳播到較為不具體的節點。
下面寫個例子:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Event Bubbling</title> 6 </head> 7 <body> 8 <button id="clickMe">Click Me</button> 9 </body> 10 </html>
然後,我們給button和它的父元素,加入點擊事件。
1 var button = document.getElementById(‘clickMe‘); 2 3 button.onclick = function() { 4 console.log(‘1. You click Button‘); 5 }; 6 document.body.onclick = function() { 7 console.log(‘2. You click body‘); 8 }; 9 document.onclick = function() { 10 console.log(‘3. You click document‘); 11 }; 12 window.onclick = function() { 13 console.log(‘4. You click window‘); 14 };
在Chrome瀏覽器運行:
如果點擊了button,那麽這個點擊事件會按如下的順序傳播
- button
- body
- document
- window
也就是說,click事件首先在<button>元素上發生,然後逐級向上傳播。
事件捕獲
事件捕獲的概念,與事件冒泡正好相反。它認為當某個事件發生時,父元素應該更早接收到事件,具體元素則最後接收到事件。比如說剛才的demo,如果是事件捕獲的話,事件發生順序會是這樣的:
- window
- document
- body
- button
事件階段(Event Phases)
當一個DOM事件觸發時,它不是在觸發的對象上只觸發一次的,而是經歷三個階段。分別為
1:一開始從文檔的根節點流向目標對象(捕獲階段)
2:然後在目標對向上被觸發(目標階段)
3:之後再回溯到文檔的根節點(冒泡階段).
1. 事件捕獲階段
事件的第一個階段是捕獲階段。事件從文檔的根節點出發,隨著DOM樹的結構向事件的目標節點流去。途中經過各個層次的DOM節點,並在各節點上觸發捕獲事件,直到到達事件的目標節點。捕獲階段的主要任務是建立傳播路徑,在冒泡階段,事件會通過這個路徑回溯到文檔跟節點。當事件發生時,首先發生的是事件捕獲,為父元素截獲事件提供了機會。
例如,我把上面的Demo中,window點擊事件更改為使用事件捕獲模式。(addEventListener最後一個參數,為true則代表使用事件捕獲模式,false則表示使用事件冒泡模式。不理解的可以去學習一下addEventListener函數的使用)
1 window.addEventListener(‘click‘, function() { 2 console.log(‘4. You click window‘); 3 }, true);
此時,點擊button的效果是這樣的。
可以看到,點擊事件先被父元素截獲了,且該函數只在事件捕獲階段起作用。
處於目標與事件冒泡階段
事件到了具體元素時,在具體元素上發生,並且被看成冒泡階段的一部分。
隨後,冒泡階段發生,事件開始冒泡。
阻止事件冒泡
事件冒泡過程,是可以被阻止的。防止事件冒泡而帶來不必要的錯誤和困擾。
這個方法就是:stopPropagation()
我們對button的click事件做一些改造。
1 button.addEventListener(‘click‘, function(event) { 2 // event為事件對象 3 console.log(‘1. You click Button‘); 4 event.stopPropagation(); 5 console.log(‘Stop Propagation!‘); 6 }, false);
點擊後,效果如下圖:
不難看出,事件在到達具體元素後,停止了冒泡。但不影響父元素的事件捕獲。
總結
事件流:描述的就是從頁面中接受事件的順序。
分有事件冒泡與事件捕獲兩種。
DOM事件流的三個階段:
- 事件捕獲階段
- 處於目標階段
- 事件冒泡階段
轉載於劉彥佐“面試整理之DOM事件階段”一文
事件冒泡