iT邦幫忙

2021 iThome 鐵人賽

DAY 15
1

前情提要

艾草:「好了,總算選取到樹上的紅色果實了,那我來教你一些簡單的火屬性魔法事件。」

「咦,我的魔力總量夠了嗎?總算能開始了嗎!」

艾草:「我琢磨著你的成長,已經夠了,你可以學初階魔法了。來想像你的手指有一股魔力,好像你前方有隱形的按鈕,去觸碰它。」

「喔喔喔喔~~有感覺了呃啊啊啊啊啊。」

(手指尖端冒出了小小的火燄,與此同時手指也被灼傷了。)

艾草:「喔,成功了耶!幫你澆水熄滅唷。」

「嗚嗚嗚,好痛。還會燙傷人!我學這個幹嘛,還不如用打火機!」

艾草:「是你現在魔力總量不足啦,對魔法事件的掌握度不夠,我們先來研讀一下事件的機制吧!」

(艾草心裡 os 當初就叫你不要選火屬性吧(๑•́ ₃ •̀๑))


Event

透過 Event 我們可以讓網站與使用者有更多的互動,但 Event 到底是什麼呢?

拿常見的彈跳式視窗來舉例好了,我們在某些網站購物時,當點擊到確認付款後,可能會跳出付款成功,而這個功能是如何實現的呢?

沒錯,就是透過 EventEvent 包含各式各樣的類型,例如剛剛提到的滑鼠點擊、又或是敲打鍵盤

等,通常都是使用者執行到某些特殊事件時 ,會去執行對應的程式碼,而今天會介紹一些常見的 Event 類型。

事件傳遞流程 Event Flow

為什麼要談到事件傳遞流程 Event Flow 呢?

今天當你開心的點擊了某顆按鈕時,你以為你只點擊到它嗎?這樣想就太天真了,其實你不僅僅點擊到它,如果延伸來看,你還點擊到它的父層、更甚者你點擊到的是整個 document

為什麼會這樣說呢?因為按鈕可能包覆在 div 內,而 div 可能包覆在 body 內,這樣層層延伸下去,其實你點擊到的是整個網頁,也因此網頁會有一定的事件傳遞流程。

而事件傳遞流程分為兩種:

  • Event Capture 事件捕獲
  • Event Bubble 事件冒泡

而 「Capture 捕獲」、「Bubble 冒泡」分別指的是你的事件就怎麼觸發的呢?讓我們先來看一張 W3C 的圖,會更清楚。

https://ithelp.ithome.com.tw/upload/images/20210929/20139066qZ0fhl1dkk.png

圖片來源:W3C

Capture Phase 捕獲

捕獲階段指得是由上而下,從最 window 到目標階段 Target Phase 的過程。

Target Phase 目標階段

目標階段指得是找到目標 Target 時。

Bubble Phase 冒泡

冒泡階段指得是由下而上,從目標階段 Target Phasewindow 的過程。

那這其中會帶來怎樣的差異呢?讓我們透過 addEventListener 監聽來了解吧。


addEventListener()

可以透過 addEventListener() 來監聽我們目前觸發的事件類型後,去執行對應的功能。

addEventListener() 有三個參數:

  1. type : 事件類型
  2. listener :對應的事件處理函式
  3. useCaptureBoolean 值,決定事件是以 true「Capture 捕獲」或 false「Bubble 冒泡」機制執行,預設為 false

事件類型要透過包覆單引號、雙引號的方式去呈現,例如:'click'

事件處理函式代表如果使用者點擊了我所監聽的按鈕時,應該會有什麼樣的功能,通常程式碼會包覆在函式內。

useCapture 設定 truefalse 的差異性,讓我們透過以下程式碼來了解:

Capture 捕獲

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);

執行後的結果:
https://ithelp.ithome.com.tw/upload/images/20210929/20139066qGp9FpuyIT.png

Bubble 冒泡

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')
});

執行後的結果:
https://ithelp.ithome.com.tw/upload/images/20210929/20139066pcwaAixlwL.png

透過此方式可以看到 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')
});

執行後的結果:

https://ithelp.ithome.com.tw/upload/images/20210929/20139066uifEBns6Ky.png

我們透過上方程式碼 console.log 印出 event 看看長怎樣吧!

可以發現是一大包的物件,而將它展開後有很多的屬性:
https://ithelp.ithome.com.tw/upload/images/20210929/201390669zMfBxHpI7.png
https://ithelp.ithome.com.tw/upload/images/20210929/20139066rmmFxmaH78.png

接下來讓我們針對常用的屬性 e.target 做介紹吧!


e.target

e.target 表示觸發事件的該元素本身,什麼意思呢?

一樣透過剛剛的程式碼 console.log 出來就知道了!

JavaScript:

//透過 querySelector 選取按鈕
const button = document.querySelector("button");
//為按鈕註冊監聽函式      //監聽點擊 //e 代表 event 可自定義參數
button.addEventListener("click", function(e) {
  console.log(e.target)
});

印出結果:
https://ithelp.ithome.com.tw/upload/images/20210929/20139066hJBgJWbjWt.png

用這樣可能看不太出來它好用在哪邊,但 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()

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 時需要特別注意,如果沒有指定 buttontype 屬性,預設就會是 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


上一篇
入門魔法 - 針對 DOM 節點的簡單操作
下一篇
入門魔法 - AJAX
系列文
JavaScript 魔法入門 - 從入門到中階觀念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言