瀏覽器原理中階
請說明瀏覽器中的事件委派、捕獲、冒泡
事件傳播的三個階段
當你點擊一個 DOM 元素,事件並不是只在那個元素上發生,而是會經歷三個階段:
Window
└─ Document
└─ <html>
└─ <body>
└─ <div> ← 1. 捕獲階段(由上而下)
└─ <button> ← 2. 目標階段(on target)
└─ <div> ← 3. 冒泡階段(由下而上)
1. 捕獲階段(Capture Phase)
事件從 window 向下傳播到目標元素。addEventListener 第三個參數設為 true 可在此階段監聽。
parent.addEventListener('click', handler, true); // 捕獲
2. 目標階段(Target Phase)
事件到達實際被點擊的元素,捕獲與冒泡監聽器都會在此執行。
3. 冒泡階段(Bubble Phase)
事件從目標元素向上傳播回 window。預設 addEventListener 在此階段監聽。
child.addEventListener('click', handler); // 冒泡(預設)
child.addEventListener('click', handler, false); // 同上
不是所有事件都會冒泡:
focus、blur、load、scroll等預設不冒泡。
停止傳播
e.stopPropagation():停止事件繼續向上冒泡(或向下捕獲)。e.stopImmediatePropagation():停止傳播,並阻止同一元素上後續的監聽器執行。
child.addEventListener('click', (e) => {
e.stopPropagation(); // 不讓事件冒泡到 parent
});
事件委派(Event Delegation)
利用冒泡的特性,把多個子元素的事件統一綁定在父元素上。
優點
- 減少事件監聽器數量,節省記憶體
- 動態新增的子元素自動受到監聽,不需重新綁定
範例
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
// 不要這樣做(每個 li 都綁一個)
document.querySelectorAll('#list li').forEach(li => {
li.addEventListener('click', handleClick);
});
// 應該這樣(委派給父層)
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('點擊了:', e.target.textContent);
}
});
取消預設行為
e.preventDefault() 取消瀏覽器的預設行為(如 <a> 跳頁、<form> 送出),與阻止冒泡是不同的概念。
小結
| 概念 | 方向 | 預設監聽 |
|---|---|---|
| 捕獲 | window → 目標 | addEventListener(_, _, true) |
| 目標 | — | 兩者都會觸發 |
| 冒泡 | 目標 → window | addEventListener(_, _) |
| 委派 | 利用冒泡在父元素統一處理 | — |
✦ AI 模擬面試
輸入你的答案,AI 即時分析精準度與改進空間
登入後即可使用 AI 評分
