艾草:「好了,总算选取到树上的红色果实了,那我来教你一些简单的火属性魔法事件。」
「咦,我的魔力总量够了吗?总算能开始了吗!」
艾草:「我琢磨着你的成长,已经够了,你可以学初阶魔法了。来想像你的手指有一股魔力,好像你前方有隐形的按钮,去触碰它。」
「喔喔喔喔~~有感觉了呃啊啊啊啊啊。」
(手指尖端冒出了小小的火焰,与此同时手指也被灼伤了。)
艾草:「喔,成功了耶!帮你浇水熄灭唷。」
「呜呜呜,好痛。还会烫伤人!我学这个干嘛,还不如用打火机!」
艾草:「是你现在魔力总量不足啦,对魔法事件的掌握度不够,我们先来研读一下事件的机制吧!」
(艾草心里 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
<<: EP 21: Custom Launch Screen for iOS
>>: Day 14 - Spring Boot & Thymeleaf
【前言】 接下来我们要进到整个 Project 重头戏中的重头戏啦,当我们都具备好图档以及 Met...
为了方便之後丢多点图进行测试,我将图片放进了 img 资料夹,并使用 glob 获得图片列表。 同时...
主要呈现实作成果 以下内容有参考教学影片,底下有附网址。 (内容包括我的不专业解说分析及在实作过程中...
如何开始D3js 方法一 使用CDN 请google搜寻D3Js到D3Js的官方网站。 滑鼠滚轮到下...
首先建立一个服务器方便之後 telegram 的 hook 来挂载 这边先从 github 建立一个...