JavaScript 事件物件:target、currentTarget 與 type
當任何的 事件 發生時,瀏覽器就會為這個事件創造一個物件,我們稱為 事件物件(Event Object)。它會提供額外資訊,依照事件類型的不同,會帶有不同的資料。在下方程式碼中,事件物件會以參數的形式傳給我們。
<div>
<input id="Btn" type="button" value="我是按鈕">
</div>document.querySelector('#Btn').addEventListener('click', (e) => {
// e: 本身包含了所有事件共同的屬性及方法
console.log(e);
});小提醒
參數名稱寫 e、evt、event 都可以,它只是個參數名;習慣上多寫 e。第一次接觸時,請直接 console.log(e) 展開看看裡面有什麼。
type
回傳一個代表此事件物件類型的字串。
<div>
<input id="Btn" type="button" value="我是按鈕">
</div>document.querySelector('#Btn').addEventListener('click', (e) => {
// type: click
console.log('type: ', e.type);
});同一個函式要處理多個事件類型時,e.type 就能派上用場:
const elemBtn = document.querySelector('#Btn');
function handler(e) {
console.log(e.type === 'mouseenter' ? '進來了' : '離開了');
}
elemBtn.addEventListener('mouseenter', handler);
elemBtn.addEventListener('mouseleave', handler);target 與 currentTarget
以下將觸發的對象改為 <div>。
<div id="Box">
<input type="button" value="我是按鈕">
</div>document.querySelector('#Box').addEventListener('click', (e) => {
// 指向觸發的 DOM 物件,也就是 <input>
console.log('target: ', e.target);
// 指向監聽的 DOM 物件,也就是 <div>
console.log('currentTarget: ', e.currentTarget);
});| 屬性 | 指向 | 何時會不同 |
|---|---|---|
e.target | 實際觸發事件的元素 | 點到子元素時 |
e.currentTarget | 掛上監聽器的元素 | 同上 |
小提醒
這組差異就是 事件委派 能成立的關鍵:監聽器掛在父層(currentTarget),但我們真正想知道的是使用者點到哪個子元素(target)。
nodeName 與 tagName
如果只是處理元素,那麼使用 tagName 和 nodeName 沒有差別。
<div>
<input id="Btn" type="button" value="我是按鈕">
</div>document.querySelector('#Btn').addEventListener('click', (e) => {
// tagName: INPUT
console.log('tagName:', e.target.tagName);
// nodeName: INPUT
console.log('nodeName:', e.target.nodeName);
});與上述的結果一樣沒有差別。
// tagName: INPUT
console.log('tagName:', document.querySelector('#Btn').tagName);
// nodeName: INPUT
console.log('nodeName:', document.querySelector('#Btn').nodeName);若對象不是元素,就有差異性了。
// tagName: undefined
console.log('tagName:', document.tagName);
// nodeName: #document
console.log('nodeName:', document.nodeName);總結
tagName 只能用在元素節點上,而 nodeName 可以用在任何 節點 上,可以說 nodeName 涵蓋了 tagName,並且具有更多的功能,因此,建議使用 nodeName。
注意
兩者回傳的名稱都是 大寫,所以比對時要寫 e.target.nodeName === 'INPUT',寫成小寫的 input 永遠不會成立。
其他常用的屬性與方法
| 成員 | 用途 |
|---|---|
e.key | 鍵盤事件中按下的按鍵,例如:Enter、a |
e.clientX / e.clientY | 滑鼠相對於可視範圍的座標 |
e.currentTarget.value | 表單元素當下的值,常用在 input、change |
e.preventDefault() | 取消該元素的預設行為 |
e.stopPropagation() | 阻止事件繼續往外傳播 |
常見問題
事件物件是誰傳進來的?
瀏覽器。事件發生時瀏覽器會建立事件物件,並在呼叫事件處理器時把它當第一個參數傳進來,習慣上寫成 e 或 event。
target 與 currentTarget 有什麼差別?
target 指向實際觸發事件的元素,也就是使用者真的點到的那個;currentTarget 指向掛上這個監聽器的元素。兩者在 事件委派 時通常不同。
nodeName 與 tagName 該用哪一個?
建議用 nodeName。tagName 只能用在元素節點上,nodeName 適用於任何節點,涵蓋範圍更廣。兩者回傳的元素名稱都是大寫。
箭頭函式裡可以用事件物件嗎?
可以,而且建議這樣做。箭頭函式沒有自己的 this,取不到觸發事件的元素,此時就用事件物件的 target 或 currentTarget 代替。
事件物件還有哪些常用成員?
常用的有 key 取得按下的按鍵、clientX 與 clientY 取得滑鼠座標、preventDefault() 取消預設行為,以及 stopPropagation() 阻止事件繼續傳播。