事件傳遞機制

DOM

DOM 全名為 Document Object Model 中文翻譯為 文件物件模型。
其實就是把 HTML 文件內的標籤、文字、圖片等等都定義成物件,而這些物件會形成一個樹狀結構,並且可以利用 JavaScript 來對 HTML 文件進操作和互動。
Image


DOM 節點 (node)

在 DOM 中,節點可以分成四種:
Document
HTML 檔的開端,所有的一切都會從 Document 開始往下進行
Element
文件內的各個標籤,像是 <div><p> 等等各種 HTML Tag 都是被歸類在 Element 裡面
Text
各個標籤內的文字內容
Attribute
各個標籤內的相關屬性,像是 class、href 等等

捕獲與冒泡

JavaScript 是事件驅動的程式語言,也就是說,當 user 對網頁做了指定動作,才會觸發程式執行動作。
前面提到 DOM 會以物件形式定義 HTML 內的元件,這些物件會連結形成一個樹狀節構,而為了操控這些物件節點,需要透過 DOM 裡面的事件傳遞機制。
當我們要獲得一個 DOM 的 click 事件時,會這樣寫:

1
2
3
4
const btn = document.getElementById('.btn')
btn.addEventListener('click', (e) => {
console.log(e )
})

裡面的 e 包含許多關於這次事件的相關參數,其中一個參數 eventPhase 表示這個事件在哪一個階段(Phase)觸發。
事件傳遞機制總共分為三大階段:

  • 捕獲階段 (Capture Phase)
    在捕獲階段,DOM 的事件會從根節點 (window) 開始往下尋找目標 (target),這個過程稱為捕獲階段 (CAPTURING_PHASE)。

  • 目標階段 (Target Phase)
    在找到目標的時候,就會是目標階段 (AT_TARGET)。

  • 冒泡階段 (Bubbling Phase)
    從子節點一路回傳到根節點,這個階段就稱作冒泡階段 (BUBBLING_PHASE)。

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

Image

用以下範例說明,在一般情況下,當點擊了 a 連結,因為傳遞機制的關係,其實會連同外層的<li><ul> 也一起被觸發。
從最外層的 <ul> 開始往下捕獲,然後找到目標 <a>,接著再冒泡回到 <ul>

停止事件傳遞 stopPropagation

在開發程式的過程中,可以加上 e.stopPropagation() 來停止冒泡事件。

用以上範例說明,我在 <a> 連結裡加入 e.stopPropagation(),點擊按鈕後會沒有反應,再對 <li> 點擊時會顯示前一個動作回傳的內容。
從回傳結果可以發現,當點擊 <a> 連結時,因為停止冒泡的關係,所以事件傳遞只到找到目標就停止,並沒有繼續回傳事件。而第二次點擊的 <li> 沒有加上 e.stopPropagation(),所以會繼續冒泡,完成整個傳遞過程。
Image

取消預設行為 preventDefault

stopPropagation() 常和 preventDefault() 搞混,但其實兩者沒什麼關係。
preventDefault() 也是 e 的點擊事件參數之一,功能是取消瀏覽器的預設行為。
舉例來說,如果想要點擊 <a> 連結又不想讓預設的超連結轉跳到別的網頁,就可以加上 e.preventDefault()

1
2
3
link.addEventListener("click", function (e) {
e.preventDefault()
});

參考文章