再探事件的三個階段

個人原文連接:再探事件的三個階段
偶然間看到一篇經典博客,文中有一個例子挺有意思,大概是: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 對象中有一個字段專門用於描述事件當前是處於哪一個階段:eventPhasepost

  • 0:當前沒有事件須要處理;動畫

  • 1:捕獲階段,事件從window傳遞到目標;spa

  • 2:命中階段,事件已經到達目標;操作系統

  • 3:冒泡階段,事件從目標傳達到最頂層的window的過程;設計

W3C標準中有一張圖描述了這個過程:

其中提到的三個階段是 capture phasetarget phasebubble phase,事件對象的傳播是根據 propagation path 進行的。完整的例子以下:
codepen

我對事件的整個生命週期的各個階段的瞭解實際上是很是有限的,我的推測以下:

  • 操做系統捕獲事件(點擊、觸摸等);

  • 瀏覽器從操做系統那裏得到事件的相關信息並生成事件對象;

  • 瀏覽器計算事件傳播的路徑;

  • 按照路徑傳播並觸發相應節點上的事件;

  • 最後由瀏覽器銷燬事件對象;

基於以上猜想,有幾點不是很明白:

  1. 爲何要設計成三個階段?

    有些地方是講的:由於歷史緣由——N公司提倡捕獲,M公司提倡冒泡,兩個公司互不妥協,因而標準組織乾脆兼容二者,讓事件跑一個來回,假若不支持某個過程則靜默出進入相關階段就好。長此以往,你們都認了這個規則,可是實際上來講讓事件跑一個來回效率上確定是不高的,並且從個人理解來看只進行捕獲或者冒泡也是合乎邏輯的。因此爲何現代瀏覽器(好比chrome)要同時支持兩種傳播方式呢?

  2. 傳播路徑如何肯定?

    上文中說到事件在傳播前,瀏覽器會先爲其計算出傳播路徑,然而DOM樹表面上看並非一棵查找二叉樹,只是一種描述層級關係的樹狀數據結構。那麼假設瀏覽器從操做系統拿到了事件的基本信息(點擊位置,哪一個鍵位,發生時間等),瀏覽器怎麼在這樣的樹狀結構中查找出一條肯定的路徑呢?遍歷固然是能夠的,可是這樣效率是否過低?若是每一個元素都有一個獨一無二的ID,對這個路徑查找問題有幫助嗎?

  3. 事件與其它過程如何交互?

    問題可能說的有點抽象,假設咱們在div元素上綁定了一個hover動畫,那麼當鼠標劃過期須要發生兩件事情:展現動畫和觸發mouseover事件。我以爲合理的設計應該是先觸發動畫再觸發事件,有兩種可能性:

    • 瀏覽器在事件傳播前觸發動畫,不管是捕獲仍是冒泡,對動畫觸發前後沒有影響;

    • 瀏覽器在在事件傳播過程當中觸發動畫,那麼動畫觸發順序可能和採用捕獲仍是冒泡有關係;


請不吝賜教。

相關文章
相關標籤/搜索