iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0
自我挑戰組

30天前端網頁基礎觀念(HTML,CSS,Javascript,blender)系列 第 29

Day 29 Javascript事件觸發後的傳遞機制(捕獲與冒泡 capturing and bubbling)

  • 分享至 

  • xImage
  •  

Javascript 是一種事件驅動 (Event-driven) 的程式語言,簡單來說就是當使用者對網頁做了一些動作才會觸發執行要做的下一個動作,也好比辦公室擺了一台電話在桌上,但是電話要是沒響,我們不會主動去「接電話」。

如果有一個按鈕被點擊後會出現對話框,那麼「點擊按鈕」這件事,就被稱作「事件」(Event)。而負責處理事件的程式通常被稱為「事件處理者」(Event Handler),也就是「啟動對話框的顯示」這個動作。

常見的事件(event)有點擊事件(click)滑鼠事件(mouse)鍵盤事件(keyboard)…。

事件流程 Event Flow

假設我今天有一個A裡面包含了一個B,這表示B也是A的一部分。

<div class="outer">A
			<div class="inner">B</div>
</div>

https://ithelp.ithome.com.tw/upload/images/20230930/20158158uU44CkyQl0.png

這表示B也是A的一部分。當我們點擊了B的時候,也代表我們也點擊到A,可以說實際上我們也點擊到整個網頁。

而事件流程 (Event Flow) 指的就是「網頁元素接收事件的順序」。

事件流程分成兩種機制:

  • 事件冒泡 (Event Bubbling)
  • 事件捕獲 (Event Capturing)

接下來會針對兩個機制分別做介紹。/images/emoticon/emoticon07.gif

事件捕獲 (Event Capturing)

在事件捕獲階段DOM的事件會從最頂層 (document) 開始往下尋找目標 (target),這個過稱稱為事件捕獲。

所以這個機制的順序是由上層往下傳遞。拿上面的A跟B例子來講就是:

<document><html><body><div class="outer">A</div><div class="inner">B</div>

事件冒泡 (Event Bubbling)

在事件冒泡階段DOM的事件會從最底層元素節點開始往上傳遞到document,這個過稱稱為事件冒泡。

所以這個機制的順序是由下層往上傳遞。一樣拿上面的A跟B例子來講就是:

<div class="inner">B</div><div class="outer">A</div><body><html><document>

那一定有人會好奇這樣子這樣子事件到底是依賴哪種機制執行? 答案是兩種機制都會執行!

圖片來源:W3C, DOM event flow

如果要用上圖來解釋的話就是:

td 的 click 事件發生時,會先走紅色的 「capture phase」。順序如下:

Documenthtmlbodytabletbodytrtd(實際被點擊的元素)

由上而下依序觸發它們的 click 事件。

接著會然後再繼續執行綠色的 「bubble phase」,反方向由 td 一路往上傳至 Document,整個事件流程到此結束。


那如果我們要如何驗證上面的A跟B的例子? 我們可以透過 addEventListener() 方法來綁定 click 事件。
其實我們所熟知的 addEventListener 還有第三個參數:true/false 可以決定你的監聽要在捕獲階段或是冒泡階段觸發。

  • 預設為 false 為監聽冒泡階段
  • 若改為 true 為監聽捕獲階段
let parent = document.querySelector(".outer");
let child = document.querySelector(".inner");

parent.addEventListener("click",function () {
		console.log("A Capturing");
},true);

parent.addEventListener("click",function () {
	    console.log("B Bubbling");
},false);

child.addEventListener("click",function () {
        console.log("B Capturing");
},true);

child.addEventListener("click",function () {
		console.log("B Bubbling");
},false);

如果我今天點到的是B(子元素)會出現:

A Capturing
B Capturing
B Bubbling
A Bubbling

如果我點到的是A(父元素)會出現:

A Capturing
B Bubbling

這樣就可以看的出來事件的傳遞機制是由父層的Capturing子層的Capturing點擊目標(target)子層的Bubbling父層的Bubbling


停止事件傳遞 (stopPropagation)

假設我想要再點到B的時候阻止事件傳遞,可以加入stopPropagation

child.addEventListener("click",function (e) {
		console.log("B Capturing");
		e.stopPropagation();
});

就會出現這樣的結果

A Capturing
B Capturing

但這還不是我們要的結果,還要加入

parent.addEventListener("click",function (e) {
		 console.log("A Capturing");
		 e.stopPropagation();
},true);

就可以得到這樣的結果

A Capturing

stopPropagation()停止事件傳遞跟preventDefault()停止預設行為很容易搞混。

stopPropagation()停止事件傳遞是停止事件的往下繼續傳遞。

preventDefault()停止預設行為

舉個例子來說a標籤是超連結預設行為是跳轉頁面,用了preventDefault()就可以停止預設行為不會被帶到另一個新的頁面了。


參考文獻

重新認識 JavaScript: Day 14 事件機制的原理

[JavaScript] Javascript 中的 DOM 事件傳遞機制:捕獲與冒泡 (capturing and bubbling)


上一篇
Day28 Javascript Event loop 事件循環
下一篇
Day30 鐵人賽30天文章總結
系列文
30天前端網頁基礎觀念(HTML,CSS,Javascript,blender)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言