昨天提到可以在 HTML 的 DOM 元素上添加事件監聽器,而今天要來講事件的傳遞機制。在 JavaScript 中,事件冒泡(event bubbling)
和 事件捕獲(event capturing)
是事件傳播中的扮演重要角色。當一個事件在 DOM 元素上觸發時,這個事件將由根元素(通常是<html>)向下傳播(捕獲)至目標元素,且由目標元素傳播(冒泡)至父元素。這兩種機制提供了事件監聽器可以選擇的不同階段,來處理事件。
以下是一個事件傳遞的流程圖。 圖片來源
事件冒泡(Event Bubbling)
是指當事件在 DOM 樹中觸發時,它會從最下層的元素開始,然後冒泡到最上層的元素。透過 addEventListener() 添加的監聽器預設會偵測冒泡階段傳遞的事件。
<div id="parent">
<button id="child">Click me!</button>
</div>
<script>
const parent = document.getElementById("parent");
const child = document.getElementById("child");
parent.addEventListener("click", () => {
console.log("Parent clicked!");
});
child.addEventListener("click", () => {
console.log("Child clicked!");
});
</script>
在這個例子中,當點擊按鈕(id 為 child)時,事件會由子元素往上冒泡的順序傳遞到父元素(id 為 parent),因此會先觸發子元素的監聽器,接著才觸發父元素的監聽器。
點擊按鈕的輸出結果:
Child clicked!
Parent clicked!
事件捕獲(Event Capturing)
與冒泡相反,事件是由最上層的元素向下層元素進行傳遞的。
可透過 addEventListener() 的第三個參數設為 true ,使監聽器偵測捕獲階段傳遞的事件。
<div id="parent">
<button id="child">Click me!</button>
</div>
<script>
const parent = document.getElementById("parent");
const child = document.getElementById("child");
parent.addEventListener("click", () => {
console.log("Parent clicked!");
}, true); // 使用事件捕獲
child.addEventListener("click", () => {
console.log("Child clicked!");
}, true);
</script>
在這個例子中,當點擊按鈕(id 為 child)時,在捕獲階段的事件由父元素(id 為 parent)依序傳遞到子元素,
因此父元素會先偵測捕獲階段的事件。
點擊按鈕的輸出結果:
Parent clicked!
Child clicked!
stopPropagation() 是一個在事件常見的方法,它用來停止事件繼續傳遞。
<div id="parent">
<button id="child">Click me!</button>
</div>
<script>
const parent = document.getElementById("parent");
const child = document.getElementById("child");
parent.addEventListener("click", () => {
console.log("Parent clicked!");
});
child.addEventListener("click", (event) => {
console.log("Child clicked!");
event.stopPropagation(); // 停止事件繼續傳遞
});
</script>
在這個例子中,當點擊按鈕(id 為 child)時,由於在子元素監聽器的回調函式中,透過「event.stopPropagation()」使事件不再繼續傳遞,因此父元素自然不會偵測到此事件了。
點擊按鈕的輸出結果:
Child clicked!
事件代理(Event Delegation)
是利用事件的冒泡機制,將事件監聽器添加到其父元素上,而不是添加到每個子元素上。這樣做的好處是減少了監聽器的數量,提高了性能,同時也使得在動態生成的子元素上處理事件變得更加容易。
<ul id="parent-list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script>
const parentList = document.getElementById("parent-list");
parentList.addEventListener("click", function(event) {
if (event.target.tagName === "LI") {
alert(`Item clicked: ${event.target.textContent}`);
}
});
</script>
以上是關於事件傳遞機制的概念,包括 事件捕獲
、事件冒泡
和 stopPropagation()
方法。另外也簡單舉例了透過 事件代理
的設計方式來簡化結構從而提升性能。話說不知不覺也來到了倒數第三天了,剩下兩天應該會來做收尾的東西了。那我們明天見~