DOM Event Flow

在開發 UI 比較複雜的網站時,新手開發者很容易遇到類似的問題,必須真正瞭解整個 Event 的運作才可以解決。

DOM Event 運作中,分別有三種階段:
– Capture Phase(補獲)
– AT_TARGET
– Bubbling Phase(冒泡)

另外這三個階段在 Event Interface 都有設定成常數。

const unsigned short      CAPTURING_PHASE                = 1;
const unsigned short      AT_TARGET                      = 2;
const unsigned short      BUBBLING_PHASE                 = 3;

DOM Event 在運作時,先從最根部的節點開始往下傳遞到 target(以 click 事件為例的話,就是點擊目標),這個階段叫做 Capture Phase
當到達了目標以後,事件會再從 target 由內往外傳回根節點,這個階段叫做 Bubbling Phase

DOM Event Flow
(圖片來源:W3C event flow

addEventListener

在 Javascript addEventListener method 的第三個參數為 useCapture,是用來決定 Event method 要在哪一個階段執行(預設是 Bubbling Phase)。

範例

<ul id="list">
    <li id="list-item">
        <a id="list-item-link" href="https://blog.johnsonlu.org/">Link</a>
    </li>
</ul>
// 使用 Capture Phase
let isCapturePhase = true;
let list = document.querySelector("#list");
let listItem = document.querySelector("#list-item");
let listItemLink = document.querySelector("#list-item-link");

list.addEventListener('click', function (e) {
    console.log('list bubbling', e.eventPhase);
}, isCapturePhase);

listItem.addEventListener('click', function (e) {
    console.log('list-item bubbling', e.eventPhase);
}, isCapturePhase);

listItemLink.addEventListener('click', function (e) {
    console.log('list-item-link bubbling', e.eventPhase);
    e.preventDefault();
}, isCapturePhase);

停止事件冒泡

Event method 中,如果使用 return false 的話,會做三件事:
1. 執行 event.preventDefault()
2. 執行 event.stopPropagation()
3. 傳回值並停止函式

Method Features
preventDefault 停止預設行為(例如點擊 <a>,不會導到 href 的網址)。
stopPropagation 停止事件傳導

範例

<ul id="list">
    <li id="list-item">
        <a id="list-item-link" href="https://blog.johnsonlu.org/">Link</a>
    </li>
</ul>
list.addEventListener('click', function (e) {
    console.log('list bubbling', e.eventPhase);
}, false);

listItem.addEventListener('click', function (e) {
    console.log('list-item bubbling', e.eventPhase);
}, false);

listItemLink.addEventListener('click', function (e) {
    console.log('list-item-link bubbling', e.eventPhase);

    // 網頁不會導到 https://blog.johnsonlu.org/
    e.preventDefault();

    // 停止事件傳導,只會執行這一個 Event method
    e.stopPropagation();
}, false);
Categories: JavaScript