DOM事件流,冒泡 | 捕獲 | 委託 ,詳解

(一)DOM事件流

① 定義

DOM事件流包括三個階段

  1. 捕獲階段
  2. 目標階段
  3. 冒泡階段

首先發生的是事件捕獲,爲截獲事件提供了機會。然後是實際的目標接收到事件。最後一個是冒泡階段,在這個階段對事件做出響應

事件發生時會在元素節點之間按照特定的順序傳播,這個傳播的過程就是DOM事件流
簡單的說:事件的傳播過程即DOM事件流

② 圖解

在這裏插入圖片描述
在這裏插入圖片描述

③ 歷史

當瀏覽器發展到第四代時(IE4及Netscape Communicator4),瀏覽器開發團隊遇到了一個很有意思的問題:頁面的哪一部分會擁有某個特定的事件?要明白這個問題問的是什麼,可以想象畫在一張紙上的一組同心圓。如果你把手指放在圓心上,那麼你的手指指向的不是一個圓,而是紙上所有的圓,兩家公司的瀏覽器開發團隊在看待瀏覽器事件方面還是一致的。如果你單擊了某個按鈕,他們都認爲單擊事件不僅僅發生在按鈕上。換句話說,在單機按鈕的同時,你也單擊了按鈕的容器元素,甚至也單擊了整個頁面。
事件流描述的是從頁面中接受事件的順序。但有意思的是,IE 和 Netscape 開發團隊居然提出了差不多完全相反的概念,IE的事件流是冒泡流,而Netscape Communicator的事件流是事件捕獲流。

(摘自《JavaScript高級程序設計》)

下面我用實例展現一下冒泡和捕獲的不同之處。

(二)冒泡

在這裏插入圖片描述
我給分別給div、section、body、html、window設置了點擊事件,然後只點擊了div,現在我們來分析一下此時的事件傳播過程

首先,進入捕獲階段,實際的目標元素(div)在捕獲階段不會接收到事件。這意味着在捕獲階段,事件從window → html → body → section就停止了。下一個階段是目標階段,於是事件在div上發生,並在事件處理中被看成冒泡的一部分。然後事件冒泡發生,事件又傳播回window。所以我們看到了下述的事件執行順序。

事件的執行順序是:
小 → 大
div → section → body → html → window

下面貼上代碼(css部分就不貼了,問題不大)

html部分

<body>
    <p>body</p>
    <section>
       <p>父盒子</p> 
        <div>子盒子</div>
    </section>
</body>

JS部分

    <script>
        var oSection = document.querySelector("section");
        var oDiv = document.querySelector("div");
        var oHtml = document.documentElement;
        var oBody = document.body;
        oDiv.addEventListener("click",function(){
            alert("我是子盒子")
        })
        oSection.addEventListener("click",function(){
            alert("我是父盒子")
        })
        oHtml.addEventListener("click",function(){
            alert("我是html")
        })
        oBody.addEventListener("click",function(){
            alert("我是body")
        })
        window.addEventListener("click",function(){
            alert("我是window")
        })
    </script>

(三)捕獲

事件捕獲如何觸發呢?
這時需要用到 addEventListener( )方法的第三個參數(默認爲false,即冒泡階段),將第三個參數改爲true,表示將此事件改爲捕獲階段。
( 如果不瞭解addEventListener( )方法的可以 查看文檔

接下來我們看一下事件在捕獲階段的觸發順序:

根據上面的代碼,我們先把父盒子section的點擊事件變爲捕獲階段

    oSection.addEventListener("click",function(){
        alert("我是父盒子")
    },true)

看看效果:
在這裏插入圖片描述
首先,進入捕獲階段,實際的目標元素(div)在捕獲階段不會接收到事件。但我們把section的點擊事件變爲了捕獲階段發生,section的點擊事件被捕獲了,所以最先觸發。 下一個階段是目標階段,於是事件在div上發生,並在事件處理中被看成冒泡的一部分。然後事件冒泡發生,事件又傳播回window。所以我們纔看到了下述的事件執行順序。

此時的執行順序是:

section → div → body → html → window

現在,我們將所有的事件都變成捕獲階段,看看效果:在這裏插入圖片描述
此時的執行順序是:

window → html → body → section → div

與冒泡階段的執行順序完全相反。

(四)在不同的階段執行事件

多數支持DOM事件流的瀏覽器都實現了一種特定的行爲:即使 “DOM2級事件” 規範明確要求捕獲階段不會涉及事件目標,但IE9,Safari,Chrome,Firefox 和 Opera9.5 以及更高版本都會在事件捕獲階段觸發事件對象上的事件。結果就是有兩個機會在目標對象上操作事件。
(摘自《JavaScript高級程序設計》)

想要了解HTML,DOM0,DOM2事件處理函數可以查看此文章

下面通過實例實踐一下:

首先,讓所有的事件在冒泡階段才觸發,然後給section綁定兩個點擊事件,一個在捕獲階段,一個在冒泡階段

  oSection.addEventListener("click",function(){
        alert("我是父盒子,我在捕獲階段被觸發了")
    },true)//捕獲階段
    oSection.addEventListener("click",function(){
        alert("我是父盒子,我在冒泡階段被觸發了")
    })

看看效果:

在這裏插入圖片描述
可以看到,section的兩個點擊事件都觸發了,一個在捕獲階段,一個在冒泡階段。

(五)提高內存和性能 – 事件委託

對 “事件處理程序過多” 問題的解決方案就是事件委託。事件委託利用了事件冒泡,只指定一個事件處理程序,就可以管理某一項類型的所有事件。例如,click事件會一直冒泡到window層次。也就是說,我們可以爲整個頁面指定一個onclick事件,而不必給每個可單擊的元素分別添加事件
(事件處理程序指響應某個事件的函數)

下面看看效果和代碼:

① 實例

在這裏插入圖片描述

JS代碼

  <script>
    window.addEventListener("click", function (e) {
        switch (e.target.className) {//我事先給每個元素設定了一個專屬class
            case "html":
                alert("我是html");
                break;
            case "body":
                alert("我是body");
                break;
            case "section":
                alert("我是父盒子");
                break;
            case "div":
                alert("我是子盒子");
                break;
        }
    })
</script>

上述代碼中,我們使用事件委託只爲window添加了一個onclick事件處理函數,由於所有的元素都是window的子節點,而且它們的事件會冒泡,所以單擊事件最終會被這個函數處理,然後通過檢測屬性的className來檢測是哪個元素被點擊,從而做出不同的動作。

上述代碼中還用到了event事件對象,target返回觸發此事件的元素。也就是說,誰觸發了window的點擊事件,target就是誰。

② 優點

上述代碼與前面未使用事件委託的代碼比一比,會發現這段代碼的事前消耗更低,因爲不需要取得DOM元素(或者只需要取得一個DOM元素),只添加了一個事件處理程序。雖然對於用戶來說最終的結果相同,但是這種技術需要佔用的內存更少。所有用到按鈕的事件(多鼠標事件和鍵盤事件)都適合採用事件委託技術。

這樣做與採取傳統的做法相比具有如下優點:

  • window對象很快就可以訪問,只要可單擊的元素呈現在頁面上,就可以立即具備適當的功能
  • 在頁面中設置事件處理程序所需的事件更少。只添加一個事件處理程序所需的DOM引用更少,所花的時間也更少
  • 整個頁面佔據的內存空間更少,能夠提升整體性能。

我的與此文章相關的文章:
1.DOM事件處理函數、DOM0,DOM2的優缺點及IE兼容

結語:若文章有錯誤的地方,煩請在評論區指出。當然,我會不定時的重新編輯寫過的文章,查錯及優化,希望能將最好的文章展現給讀者。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章