自學日記

學習程式相關知識及學習法

0%

JS 事件傳遞

事件傳遞

說明事件傳遞的流程及事件三個階段及阻止事件冒泡

“JavaScript 是一個事件驅動 (Event-driven) 的程式語言,當瀏覽器載入網頁開始讀取後,雖然馬上會讀取 JavaScript 事件相關的程式碼,但是必須等到「事件」被觸發(如使用者點擊、按下鍵盤等)後,才會再進行對應程式的執行。””–重新認識 JavaScript: Day 14 事件機制的原理

事件流程 Event Flow

以div元素說明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    <style>
#A {
width: 300px;
height: 300px;
background-color: green;
}
#B {
width: 200px;
height: 200px;
background-color: red;
}
#C {
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
<!--設定外層Adiv,包裹內層Bdiv -->
<div id="A">
<div id="B">
<div id ="C"></div>
</div>
</div>

在點擊(Click)黃色 C div時,我們等同於點擊了紅色B div、綠色的A div**(因為A div包裹著B div,B div包裹著C div),也可視為點擊了整個網頁,
因此
網頁元素接收事件的順序**為事件流程。

事件的三個階段

捕獲階段(Capture Phase)

事件從根節點流向目標節點,途中流經各個DOM節點,在各個節點上觸發捕獲事件,直到達到目標節點。(由外而內)

目標階段(Target Phase)

事件到達目標節點時,就到了目標階段,事件在目標節點上被觸發

冒泡階段(Bubbling Phase)

事件在目標節點上觸發後,不會終止,一層層向上冒,回溯到根節點。(由內而外)

經過上面三個階段解釋,我們以W3C DOM Event的圖片來看整體流程

利用事件監聽EventTarget.addEventListener()做階段監聽

明白整體流程後,我們由剛才舉例事件流程的範例繼續延伸,釐清我們的點擊過程,以驗證捕獲過程及冒泡過程的先後順序:

我們預期點擊黃色方塊(C div)反應,因此撰寫事件監聽

  • Html及Css上面程式撰寫了,因此本次著重撰寫在javascript上:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    var div = document.getElementById("A"); 
    var div = document.getElementById("B");
    var div = document.getElementById("C");

    //參數一般無撰寫會默認是false,為事件冒泡"模式",
    //這裡為求清楚撰寫出false
    A.addEventListener('click', function (event) {
    console.log('A');
    },false);
    B.addEventListener('click', function (event) {
    console.log('B');
    },false);
    C.addEventListener('click', function (event) {
    console.log('C');
    },false);

    //參數設为true為事件捕獲"模式"
    A.addEventListener('click', function (event) {
    console.log('A');
    }, true);
    B.addEventListener('click', function (event) {
    console.log('B');
    }, true);
    C.addEventListener('click', function (event) {
    console.log('C');
    }, true);

    點擊後反應為:

注意!code內,我們特意撰寫冒泡過程為先,但是跑出的反應卻是補獲過程先啟動
因此我們明白:

捕獲及冒泡事件皆會執行,先捕獲階段,再來是冒泡階段

阻止事件冒泡

也可以稱為取消事件傳遞,因為上述事件流程中,我們在點擊時會同時觸發外層的div,我們不希望這樣的冒泡事件發生,因此如何中斷事件冒泡傳遞,可使用方法為event.stopPropagation():

  • 以上述相同的javascript code 繼續撰寫,以冒泡過程做示範:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
            A.addEventListener('click', function (event) {
    console.log('A');
    },false);
    B.addEventListener('click', function (event) {
    // 加上阻止事件,另外funtion(event)可縮寫為function(e),但初學者建議寫完整。
    event.stopPropagation();
    console.log('B');
    },false);
    C.addEventListener('click', function (event) {
    console.log('C');
    },false);
    點擊後,事件流程將會停留在B階段

參考資料:事件的三個階段:捕獲階段目標階段冒泡階段