iT邦幫忙

0

DOM事件流 (Event Flow)中的捕獲期(Capturing Phase)、目標(Target Phase)、冒泡期(Bubbling Phase)

  • 分享至 

  • xImage
  •  

捕獲、目標、冒泡 只有在使用 DOM 的方法才會出現。

事件流的概念 (捕獲、目標、冒泡) 是 DOM 規範的一部分,它專門適用於處理由瀏覽器產生的、作用於 DOM 樹結構上的事件。簡單來說,只要在HTML元素上觸發一個事件,就一定會發生這件三件事,捕獲期、目標期、冒泡期,順序從左到右是固定的,而發生這三件事情就是等於發生DOM事件流(Event Flow)。

常見的例子有使用addEventListener加事件監聽器(還有滑鼠事件、鍵盤事件、表單事件、拖放事件等等...)後,可以用js執行程式碼,對監聽的元素做什麼事情等,也是這邊討論的一個觸發事件。即使HTML沒有在任何元素綁定任何監聽器,這個事件流仍然會發生,只是沒有程式碼去響應它而已。

捕獲期(Capturing Phase)

概念: 事件從 document 根部開始,向下 傳播到事件實際發生的元素(目標元素)的過程。
順序: 從最外層的父元素開始,逐級向下傳遞給子元素。
啟用方式: 在 addEventListener 中將第三個參數設為 true(或傳遞一個選項物件 {capture: true})。
舉例: 點擊C元素時,事件會先經過A,再經過B,最後到C。
用途: 可以在事件到達目標元素之前 攔截事件。

目標(Target Phase)

概念: 事件到達並在其 實際發生 的元素上觸發的階段。
順序: 這是事件流的中心點。
舉例: 點擊C元素時,事件在C元素上觸發。
用途: 這是處理事件的主要場所。

冒泡期(Bubbling Phase)

概念: 事件從 目標元素 開始,向上 傳播到 document 根部的過程。
順序: 從目標元素開始,逐級向上傳遞給父元素,直到最外層。
啟用方式: 在 addEventListener 中將第三個參數設為 false(或省略,因為這是預設值)。
舉例: 點擊C元素時,事件會從C,再到B,最後到A。
用途: 這是 預設且最常用 的事件處理方式,通常用於 事件委派(Event Delegation)。

(這邊假設範例HTML中,A是最外層,A的內層為B,B的內層為C)。
捕獲期: A > B > C(事件向下)
目標: 觸發C上的監聽器
冒泡期: C > B > A(事件向上)

語法 :element.addEventListener(type, listener, useCapture)

useCapture為布林值 (true/false) true:事件在捕獲期觸發。 false:事件在冒泡期觸發(預設值)。

捕獲階段範例:

HTML


<div id="parent">
    <button id="child">點我</button>
</div>

JavaScript

const parent = document.getElementById('parent');
const child = document.getElementById('child');

// 1. 給子元素綁定事件 (目標/冒泡階段都會觸發)
child.addEventListener('click', function() {
    console.log("子元素按鈕被點擊了!"); 
});

// 2. 給父元素綁定捕獲事件 (useCapture: true)
parent.addEventListener('click', function(event) {
    console.log("父元素在捕獲階段攔截到事件。");
    
    // **關鍵動作:停止傳播**
    event.stopPropagation(); 
    console.log("父元素:我已經把事件攔下來了,不許再往下傳!");
}, true); // <- 設置為 true,在捕獲階段觸發

點擊結果:
當你點擊 子元素 按鈕時:

事件發生: 點擊事件從 document 開始向下傳播。

捕獲觸發: 事件到達 parent 時,父元素的捕獲處理器(程式碼 2)被執行。

攔截成功: event.stopPropagation() 立即生效,事件傳播被終止。

結果: 事件永遠無法傳播到 child 元素。

終端輸出:

父元素在捕獲階段攔截到事件。
父元素:我已經把事件攔下來了,不許再往下傳!
子元素按鈕被點擊了, 這行永遠不會出現。

冒泡階段範例:

HTML

<div id="parent">
  <button id="child">點我</button>
</div>

JavaScript

const parent = document.getElementById('parent');
const child = document.getElementById('child');

// **子元素** 上的監聽器:會先觸發
child.addEventListener('click', function() {
    console.log('子元素 button 被點擊了 (冒泡期)');
}, false); // 或省略第三個參數

// **父元素** 上的監聽器:會在子元素之後觸發 (向上冒泡)
parent.addEventListener('click', function() {
    console.log('父元素 div 接收到冒泡的點擊事件');
}); // 省略第三個參數,預設為 false (冒泡)

// 執行順序:button (冒泡) -> div (冒泡)

總結就跟開頭說的一樣,在HTML元素上觸發一個事件,就一定會發生DOM 事件流 (Event Flow),
但如果你沒有要對監聽的元素做某件事情,那他也不會給你任何顯示或改變,不過通常在元素加監聽器,
就是打算要在元素觸發事件時(ex:滑鼠事件、鍵盤事件、表單事件、拖放事件等等...),做什麼事情,
所以可以看到以上範例,打算在觸發click滑鼠事件後,對元素做 console.log 或 event.stopPropagation。
/images/emoticon/emoticon28.gif


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言