Spirit帶你徹底瞭解事件捕獲和冒泡機制

CodeSpirit發表於2021-09-18

Dom標準事件模型

在Dom標準事件模型中,事件是先進行捕獲,達到目標階段時,在進行冒泡的

捕獲階段==>目標階段==>冒泡階段

image-20210914235653177

目標元素和非目標元素

在介紹事件捕獲和事件冒泡前

我們先要了解一下目標元素和非目標元素是什麼意思

  • 目標元素:它是我們當前觸發事件的元素
  • 非目標元素:它是在捕獲階段或著冒泡階段中因為繫結了同型別的事件而觸發的元素
  • 每個Dom元素可以繫結多個事件,前提是使用addEvenetListener去新增事件,即使是相同的事件,也可以重複繫結.

事件捕獲

從頁面的根元素開始 一層一層的往下尋找

可以看下我在最上面畫的那張圖

事件冒泡

從目標元素一直往上尋找

可以看下我在最上面的那張圖

addEventListener

addEventListener可以傳入第三個引數useCapture,預設是false

其實還有一個option引數可以傳遞,但是我沒細看,因為目前我看了,我也不知道應用場景,所以打算有需求了,後面在看

  • useCapture引數會false時,預設是捕獲階段 不會觸發事件監聽,會在冒泡階段觸發事件監聽
  • useCapture引數會true時,事件監聽時從捕獲階段開始,但是冒泡階段不會觸發事件監聽

舉例說明

現在我們來分析一道題, 佈局程式碼都在下面了

HTML程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .c {
        width: 200px;
        height: 200px;
        background-color: orange;
    }
</style>

<body>
    <div class="a">
        a
        <div class="b">
            b
            <div class="c">c</div>
        </div>
    </div>
</body>
    
<script src="./script.js"></script>
</html>

JS程式碼

const a = document.querySelector(".a");
const b = document.querySelector(".b");
const c = document.querySelector(".c");




a.addEventListener("mousedown", () => {
    alert("彈出a");
}, false)
b.addEventListener("mousedown", (e) => {
    alert("彈出b");
}, true)

c.addEventListener("mousedown", (e) => {
    console.log(e)
    alert("mousedown2");
}, true)
c.addEventListener("mousedown", (e) => {
    alert("mousedown1");
}, false)
c.addEventListener("mousedown", (e) => {
    console.log(e)
    alert("mousedown3");
}, false)
c.addEventListener("mousedown", (e) => {
    console.log(e)
    alert("mousedown4");
}, true)

分析

  1. 從HTML來看,巢狀層級是 a>b>c

  2. 現在來看JS程式碼

  3. a,b,c都繫結了mousedown事件,我們仔細看下,這個的執行順序是怎麼樣的?

  4. 我可以在給你們分析一下

  5. 對於同一個元素,繫結多個事件,無論是一樣的事件,還是不一樣的事件,只要是觸發了對應事件的監聽器,那麼它都會執行

  6. 那麼同一個事件的執行順序是怎麼樣的呢?

  7. 同一個事件的執行順序是根據定義的順序來執行的,前提是useCapture保持一致

  8. 當我們點選目標元素時,我們是處於目標階段的,而不是處於冒泡階段或者捕獲階段,這一句話請牢牢記住

  9. 處於目標階段時,當useCapture有true,又有false的階段時
    這個時候 我們可以理解為目標元素其實是形成了一個類似於Dom事件模型的東西.
    在這個模型內,也有捕獲階段和冒泡階段.
    所以如果有true的話,會先執行捕獲階段,按照定義順序
    然後執行fasle階段,也就是冒泡階段,按照事件的定義順序

  10. 所以在目標階段執行的時候,這麼多事件的執行順序就是 mousedown2 mousedown4 mousedown1 mousedown3

  11. 那麼我們現在可以看下這個整個HTML頁面,這個執行順序是什麼樣的呢?

  12. 其實和目標階段的執行是一樣的
    非目標元素的useCapture為true時,捕獲階段會先執行事件監聽
    非目標元素的useCapture為false時,會在捕獲階段和目標階段執行完畢後,在冒泡階段執行事件監聽
    舉個例子,如果我在b身上也繫結了多個相同型別的事件,在有true,有false的情況下,它會先執行true的,false的不會等true執行完畢後就立馬執行,而是等待目標階段執行完畢後,才繼續執行
    大家如果不信的,可以自己去嘗試一下

  13. 所以整體的執行順序是

    b mousedown2 mousedown4 mousedown1 mousedown3 a

圖解

我怕大家還是不明白我說的是什麼意思
所以我畫了這張圖,把這個過程給大家詳細介紹一下

image-20210915110603594

相關文章