JS30-25-Event-Capture-Propagation-Bubbling-and-Once

了解 addEventListener 的運作

目標

  • 了解 addEventListener 的運作
    • 事件冒泡 (Event Bubbling)
      • 停止冒泡行為 e.stopPropagation()
    • 事件捕獲 (Event Capturing)
    • 單次觸發

成品

[DEMO] | [GitHub]


學習紀錄

事件傳遞順序

使用 addEventListener 時,不管是設定 Event BubblingEvent Capturing
當Event被觸發時,都是會先從 最外層DOM 走到 target的DOM 然後再走回 最外層DOM
所以當你設定

  • Event Bubbling(綠色路徑):只回傳 target的DOM →→ 最外層DOM 的路徑
  • Event Capturing(紅色路徑):只回傳 最外層DOM →→ target的DOM 的路徑

所以根據上面的規則,套用在下面的案例的話

HTML
1
2
3
4
5
6
7
8
9
<div class="one purple">
紫色
<div class="two pink">
粉色
<div class="three orange">
橘色
</div>
</div>
</div>

事件冒泡 (Event Bubbling):只回傳 target的DOM →→ 最外層DOM 的路徑

事件冒泡 (Event Bubbling)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function logText(e) {
// 印出當前div的class name
console.log(this.classList.value);
}

// 第三個參數 useCapture:預設為 false → 事件冒泡 (Event Bubbling)
divs.forEach(div => div.addEventListener('click', logText));

/*
console列出順序為(target的DOM →→ 最外層DOM)

three orange
two pink
one purple
*/

事件捕獲 (Event Capturing):只回傳 最外層DOM →→ target的DOM 的路徑

事件捕獲 (Event Capturing)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function logText(e) {
// 印出當前div的class name
console.log(this.classList.value);
}

// 第三個參數 useCapture 修改為 true → 事件捕獲 (Event Capturing)
divs.forEach(div => div.addEventListener('click', logText, true));

/*
console列出順序為(最外層DOM →→ target的DOM)

one purple
two pink
three orange
*/

停止冒泡行為 e.stopPropagation()

有時只是想單純針對單一元素監聽,不想因為事件冒泡的行為,
而去觸發到其他元素,這時就可利用 e.stopPropagation() 來達成此需求。

e.stopPropagation()
1
2
3
4
5
6
function logText(e) {
console.log(this.classList.value);

// 停止冒泡行為!
e.stopPropagation();
}
注意:
使用 e.stopPropagation() 僅針對 事件冒泡 (Event Bubbling) 設定,
若是設定為 事件捕獲 (Event Capturing) 的話,則不適用 e.stopPropagation()

單次觸發

once 屬性:當第一次被觸發後,就會移除本身的監聽事件,後續就沒有監聽事件。

目前想到的可運用在表單submit後,解除監聽事件,避免重覆送單。

單次觸發
1
2
3
4
5
6
7
// 在 button 的 addEventListener 第三個參數裡,設定 once 的屬性
// 當第一次被觸發後,就會移除本身的監聽事件,後續就沒有監聽事件。
button.addEventListener('click', () => {
console.log('Click!!!');
}, {
once: true
});