個人原文連接:再探事件的三個階段
偶然間看到一篇經典博客,文中有一個例子挺有意思,大概是:html
<div id="p">parent</div> <script> var p = document.getElementById('p'); p.addEventListener('click', function(e) { alert('parent節點冒泡') }, false); p.addEventListener('click', function(e) { alert('parent節點捕獲') }, true); </script>
問點擊div時,事件觸發的順序是什麼?chrome
根據事件的三個階段,我最初推測應該是先觸發捕獲事件再觸發冒泡事件,但實際結果倒是先彈出冒泡再彈出捕獲。這是爲何呢?
事情先要從 addEventListener()
方法提及,MDN文檔中關於此方法有明確描述:瀏覽器
若是事件監聽器剛好註冊到了事件目標上,那麼這個事件會處於「目標階段」,而不是冒泡階段或者捕獲階段。在目標階段的事件會觸發全部的監聽器,而不在意這個監聽器到底在註冊時 useCapture 參數值是什麼。數據結構
也就是說若是咱們直接單擊目標,那麼當事件被觸發時,event target正處於第二階段,這時全部的事件按照註冊前後順序觸發,與是否設置第三個參數無關。dom
event 對象中有一個字段專門用於描述事件當前是處於哪一個階段:eventPhase:post
0:當前沒有事件須要處理;動畫
1:捕獲階段,事件從window傳遞到目標;spa
2:命中階段,事件已經到達目標;操作系統
3:冒泡階段,事件從目標傳達到最頂層的window的過程;設計
W3C標準中有一張圖描述了這個過程:
其中提到的三個階段是 capture phase
,target phase
,bubble phase
,事件對象的傳播是根據 propagation path 進行的。完整的例子以下:
codepen
我對事件的整個生命週期的各個階段的瞭解實際上是很是有限的,我的推測以下:
操做系統捕獲事件(點擊、觸摸等);
瀏覽器從操做系統那裏得到事件的相關信息並生成事件對象;
瀏覽器計算事件傳播的路徑;
按照路徑傳播並觸發相應節點上的事件;
最後由瀏覽器銷燬事件對象;
基於以上猜想,有幾點不是很明白:
爲何要設計成三個階段?
有些地方是講的:由於歷史緣由——N公司提倡捕獲,M公司提倡冒泡,兩個公司互不妥協,因而標準組織乾脆兼容二者,讓事件跑一個來回,假若不支持某個過程則靜默出進入相關階段就好。長此以往,你們都認了這個規則,可是實際上來講讓事件跑一個來回效率上確定是不高的,並且從個人理解來看只進行捕獲或者冒泡也是合乎邏輯的。因此爲何現代瀏覽器(好比chrome)要同時支持兩種傳播方式呢?
傳播路徑如何肯定?
上文中說到事件在傳播前,瀏覽器會先爲其計算出傳播路徑,然而DOM樹表面上看並非一棵查找二叉樹,只是一種描述層級關係的樹狀數據結構。那麼假設瀏覽器從操做系統拿到了事件的基本信息(點擊位置,哪一個鍵位,發生時間等),瀏覽器怎麼在這樣的樹狀結構中查找出一條肯定的路徑呢?遍歷固然是能夠的,可是這樣效率是否過低?若是每一個元素都有一個獨一無二的ID,對這個路徑查找問題有幫助嗎?
事件與其它過程如何交互?
問題可能說的有點抽象,假設咱們在div元素上綁定了一個hover動畫,那麼當鼠標劃過期須要發生兩件事情:展現動畫和觸發mouseover事件。我以爲合理的設計應該是先觸發動畫再觸發事件,有兩種可能性:
瀏覽器在事件傳播前觸發動畫,不管是捕獲仍是冒泡,對動畫觸發前後沒有影響;
瀏覽器在在事件傳播過程當中觸發動畫,那麼動畫觸發順序可能和採用捕獲仍是冒泡有關係;
請不吝賜教。