艾草:「好了,總算選取到樹上的紅色果實了,那我來教你一些簡單的火屬性魔法事件。」
「咦,我的魔力總量夠了嗎?總算能開始了嗎!」
艾草:「我琢磨著你的成長,已經夠了,你可以學初階魔法了。來想像你的手指有一股魔力,好像你前方有隱形的按鈕,去觸碰它。」
「喔喔喔喔~~有感覺了呃啊啊啊啊啊。」
(手指尖端冒出了小小的火燄,與此同時手指也被灼傷了。)
艾草:「喔,成功了耶!幫你澆水熄滅唷。」
「嗚嗚嗚,好痛。還會燙傷人!我學這個幹嘛,還不如用打火機!」
艾草:「是你現在魔力總量不足啦,對魔法事件的掌握度不夠,我們先來研讀一下事件的機制吧!」
(艾草心裡 os 當初就叫你不要選火屬性吧(๑•́ ₃ •̀๑))
透過 Event
我們可以讓網站與使用者有更多的互動,但 Event
到底是什麼呢?
拿常見的彈跳式視窗來舉例好了,我們在某些網站購物時,當點擊到確認付款後,可能會跳出付款成功,而這個功能是如何實現的呢?
沒錯,就是透過 Event
,Event
包含各式各樣的類型,例如剛剛提到的滑鼠點擊、又或是敲打鍵盤
等,通常都是使用者執行到某些特殊事件時 ,會去執行對應的程式碼,而今天會介紹一些常見的 Event
類型。
為什麼要談到事件傳遞流程 Event Flow 呢?
今天當你開心的點擊了某顆按鈕時,你以為你只點擊到它嗎?這樣想就太天真了,其實你不僅僅點擊到它,如果延伸來看,你還點擊到它的父層、更甚者你點擊到的是整個 document
。
為什麼會這樣說呢?因為按鈕可能包覆在 div
內,而 div
可能包覆在 body
內,這樣層層延伸下去,其實你點擊到的是整個網頁,也因此網頁會有一定的事件傳遞流程。
而事件傳遞流程分為兩種:
而 「Capture 捕獲」、「Bubble 冒泡」分別指的是你的事件就怎麼觸發的呢?讓我們先來看一張 W3C 的圖,會更清楚。
圖片來源:W3C
捕獲階段指得是由上而下,從最 window
到目標階段 Target Phase
的過程。
目標階段指得是找到目標 Target
時。
冒泡階段指得是由下而上,從目標階段 Target Phase
到 window
的過程。
那這其中會帶來怎樣的差異呢?讓我們透過 addEventListener
監聽來了解吧。
可以透過 addEventListener()
來監聽我們目前觸發的事件類型後,去執行對應的功能。
addEventListener()
有三個參數:
type
: 事件類型listener
:對應的事件處理函式useCapture
:Boolean
值,決定事件是以 true
「Capture 捕獲」或 false
「Bubble 冒泡」機制執行,預設為 false
。事件類型要透過包覆單引號、雙引號的方式去呈現,例如:'click'
。
事件處理函式代表如果使用者點擊了我所監聽的按鈕時,應該會有什麼樣的功能,通常程式碼會包覆在函式內。
而 useCapture
設定 true
、 false
的差異性,讓我們透過以下程式碼來了解:
HTML:
<table>
<thead>
</thead>
<tbody>
<tr>
<td>123</td>
<td>321</td>
</tr>
</tbody>
</table>
JavaScript:
const table = document.querySelector("table");
const tbody = document.querySelector("tbody");
const tr = document.querySelector("tr");
const td = document.querySelector("td");
table.addEventListener("click", function(e) {
console.log('table click')
},true);
tbody.addEventListener("click", function(e) {
console.log('tbody click')
},true);
tr.addEventListener("click", function(e) {
console.log('tr click')
},true);
td.addEventListener("click", function(e) {
console.log('td click')
},true);
執行後的結果:
false
為預設情況。
HTML:
<table>
<thead>
</thead>
<tbody>
<tr>
<td>123</td>
<td>321</td>
</tr>
</tbody>
</table>
JavaScript:
const table = document.querySelector("table");
const tbody = document.querySelector("tbody");
const tr = document.querySelector("tr");
const td = document.querySelector("td");
table.addEventListener("click", function(e) {
console.log('table click')
});
tbody.addEventListener("click", function(e) {
console.log('tbody click')
});
tr.addEventListener("click", function(e) {
console.log('tr click')
});
td.addEventListener("click", function(e) {
console.log('td click')
});
執行後的結果:
透過此方式可以看到 Capture 捕獲、Bubble 冒泡的差異, Capture 捕獲是從父層一層一層下來時就觸發動作,Bubble 冒泡則是從子層一層一層上去時觸發動作。
接下來讓我們實作看看註冊監聽點擊按鈕事件吧!
HTML:
<button type = "button">按鈕</button>
JavaScript:
//透過 querySelector 選取按鈕
const button = document.querySelector("button");
//為按鈕註冊監聽函式 //監聽點擊 //e 代表 event 可自定義參數
button.addEventListener("click", function(e) {
console.log('button click')
});
執行後的結果:
我們透過上方程式碼 console.log
印出 event
看看長怎樣吧!
可以發現是一大包的物件,而將它展開後有很多的屬性:
接下來讓我們針對常用的屬性 e.target
做介紹吧!
e.target
表示觸發事件的該元素本身,什麼意思呢?
一樣透過剛剛的程式碼 console.log
出來就知道了!
JavaScript:
//透過 querySelector 選取按鈕
const button = document.querySelector("button");
//為按鈕註冊監聽函式 //監聽點擊 //e 代表 event 可自定義參數
button.addEventListener("click", function(e) {
console.log(e.target)
});
印出結果:
用這樣可能看不太出來它好用在哪邊,但 e.target
常常拿來取值,或是拿來做流程判斷,以下舉例:
例如當大範圍監聽時,搭配 e.target
底下的屬性 nodeName
判斷點擊到的是不是按鈕:
HTML:
<ul class="list">
<button type="button">送出</button>
</ul>
JavaScript:
const list = document.querySelector(".list");
list.addEventListener("click", function (e) {
if(e.target.nodeName === "BUTTON"){
console.log("我點擊到的是按鈕!")
}
});
透過 e.target
搭配 nodeName
的方式可以確認當點擊到的是按鈕時,才開始撰寫對應的效果!
event.preventDefault()
可以拿來阻擋預設行為,例如 a
連結點擊會轉址的行為,又或者是表單的
submit
效果,以下來示範該如何實作!
HTML:
<a href="https://www.google.com.tw/">連結</a>
JavaScript:
const link = document.querySelector("a");
link.addEventListener("click", function (e) {
//阻擋 a 連結轉址效果
e.preventDefault();
console.log("我被點了")
});
像這樣直接在 link 的註冊監聽函式內放入 event.preventDefault()
a
連結就不會有轉址的效果囉!
另外如果使用 button
時需要特別注意,如果沒有指定 button
的 type
屬性,預設就會是 submit
,要特別留意。
請問以下敘述何者錯誤?
A addEventListener()
useCapture
參數設定 true
時,會透過 Capture 捕獲機制執行
B Capture 捕獲機制會由父層到子層觸發,且 addEventListener()
useCapture
參數預設就是 true
C e.target
表示觸發事件的元素本身
D event.preventDefault()
可以阻擋預設行為,例如表單的 submit
效果
解答:選項 B 錯誤,因為useCapture
參數預設為 false
,預設是透過 Bubble 冒泡執行。
JavaScript 必修篇 - 前端修練全攻略(六角學院)
https://ithelp.ithome.com.tw/articles/10192015
https://medium.com/itsems-frontend/javascript-event-bubbling-capturing-794cd2d01e61