Article directory
I have been typing code for too long. I can’t remember all the knowledge I remembered very clearly when I was studying. The more I learn, the more I can’t.
I don't know how long it will last...
what is event flow
了解什么是事件流,主要的是了解 ·事件·的概念:
- 前端页面的交互主要就是由事件驱动来实现的;
- 而类似于 dom的 click、change,浏览器的 onload, 键盘的 keypress都可以称之为事件。
- 想要具体了解的话,可以去看《JavaScript权威指南》的第17章。
js的事件流指的是:
- 事件的流向: 浏览器响应一个 `事件` 的执行顺序。
- 主要分为三个阶段(与上图对应):
1. 捕获阶段: 从文档的最底层(document)向上查询事件源,直到查询到事件源,这段时间都是捕获阶段(①~④);
2. 目的阶段: 捕获阶段改变至冒泡阶段的时段(④);
3. 冒泡阶段(处理事件的阶段): 由事件源向下冒泡,直到冒泡文档(document)之后,冒泡结束(④~⑦)。
give a chestnut
Take a simple example of click to illustrate:
<!DOCTYPE html>
<html lang="en" onclick="clickHandle('html', event)">
<head>
<style>
#app {
background-color: red;
color: #ccc;
}
</style>
</head>
<body onclick="clickHandle('body', event)">
<div id="app" onclick="clickHandle('#app', event)">
<button onclick="clickHandle('button', event)">按钮</button>
</div>
</body>
<script>
function clickHandle(msg, e) {
console.log(`\`${
msg}\` 被点击了`, e);
}
</script>
</html>
/**
* 上面的代码主要是给 'html' > 'body' > '#app' > 'button', 添加了一个点击事件 'click',对应的DOM事件触发后会console一条提示信息;
*
* 而根据我们上面说明的事件流向的话:
* - 当我们点击了 <button> 按钮,我们的console顺序应该是:
* 1. 捕获阶段: html -> body -> #app -> button
* 2. 目标阶段:button
* 3. 冒泡阶段:button -> #app -> body -> html
* html -> body -> #app -> button -> button -> button -> #app -> body -> html (除button外,每个dom触发两次)
**/
Execute 100 million times
to output four sentences! ? impossible! ! The code I wrote must be correct! ! !
Spam browser! Gan! ! !
Browser Default Event Behavior
其实很简单就能想通了。
- 要是事件流的每一步都触发,那每一个dom事件都要触发两次至少,但是普遍我们只需要一次;
- 所以这里的话浏览器普遍默认的是只执行事件流的 '冒泡阶段';
- 能解(忽)释(悠)通了
- 事实就是这样的
trigger capture phase
如果需要我们的事件在捕获阶段就触发呢:
这个时候就需要用到 ‘addEventListener’ ,设置第三个参数当为 true 时,就触发于捕获阶段;
那我们在给每一个DOM添加一个;
<!DOCTYPE html>
<html lang="en" onclick="clickHandle('html', event)">
<head>
<style>
#app {
background-color: red;
color: #ccc;
}
</style>
</head>
<body onclick="clickHandle('body', event)">
<div id="app" onclick="clickHandle('#app', event)">
<button onclick="clickHandle('button', event)">按钮</button>
</div>
</body>
<script>
function clickHandle(msg, e) {
console.log(`\`${
msg}\` 被点击了`, e);
}
document.querySelector("button").addEventListener('click', (e) => clickHandle('capture: button', e), true);
document.querySelector("#app").addEventListener('click', (e) => clickHandle('capture: #app', e), true);
document.querySelector("body").addEventListener('click', (e) => clickHandle('capture: body', e), true);
document.querySelector("html").addEventListener('click', (e) => clickHandle('capture: html', e), true);
</script>
</html>
Run it:
it works
, but there is a small problem that needs to be noticed. The above is the result of running Google Chrome; the
following is the result of running QQ Browser, Firefox, and Google Dual-Core Browser.
Finally, there are some small differences in the target element, but Not a big problem (keep an eye out).
Possible problems on the project (cancel the browser's default behavior)
- Nesting of elements; such as nuts in our example, no no. . .
- For example, in our example, clicking the button only requires console, and clicking #app requires only alert;
- But if written as above,
- When clicking #app, it is correct;
- When the button is clicked, console + alert will appear (bubble event triggered) something went wrong! ! !
- At this time, we don't need the button to trigger the bubbling event; so we need to cancel the browser's default behavior;
// 阻止冒泡事件
if (e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true; // 兼容 IE8-
}
// vue的话,使用修饰符就可以了 https://cn.vuejs.org/v2/api/#v-on
// <button @click.stop="btnClick">按钮</button>
all codes
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#app {
background-color: red;
color: #ccc;
}
</style>
</head>
<body>
<div id="app">
<button>按钮</button>
</div>
</body>
<script>
let appDom = document.getElementById("app");
let btnDom = document.querySelector("button");
appDom.addEventListener('click', appClick);
btnDom.addEventListener('click', btnClick);
function btnClick(e) {
e.stopPropagation(); // 马上2022了,微软都自己放弃ie了,就不要让它来祸害我们前端了。。。
console.log('btn 被点击了')
}
function appClick() {
alert("app 被点击了");
}
</script>
</html>