tags: JavaScript front-end Event Handling
[Note] Event Handling
addEventListener()的參數
addEventListener(type, listener);
addEventListener(type, listener, options);
addEventListener(type, listener, useCapture);
Event Type:string,事件的類型,例如: click。Event Listener:function,事件執行時觸發的函式。useCapture: boolean,決定事件是以「捕獲」或「冒泡」機制執行,預設為 false (冒泡)。
取消事件傳遞 - e.stopPropagation
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing', e.eventPhase);
e.stopPropagation();
}, true)
// console
list capturing
1
// 若是同一個節點上有不只一個 listener,還是會被執行到
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing');
e.stopPropagation();
}, true)
// list 的捕獲 2
$list.addEventListener('click', (e) => {
console.log('list capturing2');
}, true)
//console
list capturing
list capturing2
若是要讓其他同一層級的 listener 也不要被執行,可以改用e.stopImmediatePropagation()
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing');
e.stopImmediatePropagation();
}, true)
// list 的捕獲 2
$list.addEventListener('click', (e) => {
console.log('list capturing2');
}, true)
// console
list capturing
取消預設行為 - e.preventDefault
- 取消瀏覽器的預設行為
// list_item_link 的冒泡
$list_item_link.addEventListener('click', (e) => {
e.preventDefault();
}, false)
- 一旦 call 了 preventDefault,在之後傳遞下去的事件裡面也會有效果。
在#list 的捕獲事件裡面就先寫了 e.preventDefault(),這個效果會在之後傳遞的事件裡面一直延續。因此,等之後事件傳遞到#list_item_link 的時候,你會發現點超連結一樣沒反應。
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing', e.eventPhase);
e.preventDefault();
}, true)
常見問題
1. 試說明事件代理 (event delegation) 的概念?
- listener 是放在父層身上。這樣透過父節點來處理子節點的事件,就叫做事件代理。
<html>
<body>
<ul id="list">
<li data-index="1">1</li>
<li data-index="2">2</li>
<li data-index="3">3</li>
</ul>
</body>
</html>
li.dataset.index
document.getElementById('list').addEventListener('click', (e) => {
console.log(e.target.getAttribute('data-index'));
})
2. 試說明事件處理中 bubble(false) 和 capture(true) 的差別 (事件的傳遞機制)。
兩個原則:
- 先捕獲,再冒泡
- 當事件傳到 target 本身,沒有分捕獲跟冒泡 ( AT_TARGET,沒有捕獲跟冒泡之分,所以執行順序就會根據你 addEventListener 的順序而定 )
事件觸發總共有三個階段:
- Capture Phase :
根節點開始往下傳遞到 target,這邊你將節點加上事件,就會處於 Capture Phase。 - Target Phase :
所點擊的目標,在 target 身上所加的 eventListenr 會是 Target Phase。 - Bubbling Phase :
最後,事件再往上從子節點(target)一路逆向傳回去根節點,就叫做 Bubbling Phase
而這邊的 e 裡面就蘊含了許多這次事件的相關參數,其中有一個叫做 eventPhase,是一個數字,表示這個事件在哪一個 Phase 觸發
const $list = document.getElementById('list');
$list.addEventListener('click', (e) => {
console.log(e.eventPhase);
})
PhaseType
const unsigned short CAPTURING_PHASE = 1;
const unsigned short AT_TARGET = 2;
const unsigned short BUBBLING_PHASE = 3;
const get = (id) => document.getElementById(id);
const $list = get('list');
const $list_item = get('list_item');
const $list_item_link = get('list_item_link');
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing', e.eventPhase);
}, true)
// list 的冒泡
$list.addEventListener('click', (e) => {
console.log('list bubbling', e.eventPhase);
}, false)
// list_item 的捕獲
$list_item.addEventListener('click', (e) => {
console.log('list_item capturing', e.eventPhase);
}, true)
// list_item 的冒泡
$list_item.addEventListener('click', (e) => {
console.log('list_item bubbling', e.eventPhase);
}, false)
// list_item_link 的捕獲
$list_item_link.addEventListener('click', (e) => {
console.log('list_item_link capturing', e.eventPhase);
}, true)
// list_item_link 的冒泡
$list_item_link.addEventListener('click', (e) => {
console.log('list_item_link bubbling', e.eventPhase);
}, false)
//console
list capturing
1
list_item capturing
1
list_item_link capturing
2
list_item_link bubbling
2
list_item bubbling
3
list bubbling
3
3. 什麼是事件物件 (event object),你在程式中如何取得與使用?
當監聽事件「發生」時,瀏覽器會去執行 Event Handler,並建立 Event Object,其中會包含許多重要的資訊。以點擊事件舉例,可以注意到幾個:
type : click,事件類型。target : input.btn,被點擊的對象。bubbles : true,表示這事件是否是在「冒泡」階段觸發。altKey : false,表示是否有按著 alt 鍵點擊。pageX / pageY,表示事件觸發時,滑鼠座標在網頁的相對位置- …etc
Advantage: 熟知 event object 可以幫助你設計更多元的互動形式,利用「event.key」去判定各種使用者點擊的狀況,進而判斷不同狀況時,該做出何種反應
const el = document.querySelector('.btn')
el.addEventListener('click', function (event) {
console.log(event)
})
JavaScriptevent handling
Published on 19 Jul 2025
Updated on 19 Jul 2025