本文参考自《JavaScript高级程序设计(第3版)》13.1节事件流。
事件模型
事件捕获
- 如果你点击了页面中的元素,那么这个点击事件会按照如下顺序传播。
document
==>html
==>body
==>div
- 即,事件会先通知给祖宗,最后通知给儿子。
事件冒泡
- 如果你单击了页面中的元素,那么这个点击事件会按照如下顺序传播。
div
==>body
==>html
==>document
- 即,事件会先通知给儿子,最后通知给祖宗。
事件机制
DOM事件机制(处理程序)
- 使用addEventListener()来指定事件处理程序,它接收三个参数;
addEventListener(监听事件类型, 事件处理函数, 布尔值)
- 其中的布尔值指明了在什么阶段调用事件处理程序
- 默认为false,表示在冒泡阶段调用事件处理程序;
- 如果设为true,表示在捕获阶段调用事件处理程序;
/* 举个例子 🌰 */
btn.addEventListener("click", () => {
alert("点击了");
}, false);
举个例子 🌰
- 源代码如下(也可以在JSBin查看)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="a">
<div id="b">
<div id="c"></div>
</div>
</div>
</body>
</html>
```javascript let a = document.getElementById(“a”); let b = document.getElementById(“b”); let c = document.getElementById(“c”);#a{
width: 300px;
height: 300px;
background: tomato;
}
#b{
width: 200px;
height: 200px;
background: orange;
}
#c{
width: 100px;
height: 100px;
background: yellow;
}
c.addEventListener(“click”, event => { console.log(“c1”); }, false);
c.addEventListener(“click”, event => { console.log(“c2”); }, true);
b.addEventListener(“click”, event => { console.log(“b”); }, true);
a.addEventListener(“click”, event => { console.log(“a1”); }, true);
a.addEventListener(“click”, event => { console.log(“a2”) }, false);
a.addEventListener(“click”, event => { console.log(“a3”); // 阻止冒泡事件和捕获事件 // 注释前后控制台输出不同 event.stopImmediatePropagation(); }, true);
a.addEventListener(“click”, event => { console.log(“a4”); }, true); ```
- 我们创建了三个盒子,并分别给他们加上一些点击事件。
【问】问题一:点击b或c,会输出什么?
【答】a1
、a3
- stopImmediatePropagation 包含了 stopPropagation 的功能,即阻止事件传播(捕获或冒泡),但同时也阻止该元素上后来绑定的事件处理程序被调用,所以不输出 a4。
- 因为事件捕获被拦截了,自然不会触发 b、c 上的事件,所以不输出 b、c1、c2,冒泡更谈不上了,所以不输出 a2。
【问】问题二:点击a,会输出什么?
【答】a1
、a2
、a3
- 比较容易出错的答案是
a1
、a3
、a2
,虽然这三个事件处理程序注册时指定了true
、false
,但现在点击的是a
这个盒子本身,它处于事件流的目标(target)阶段,不是冒泡阶段、也不是捕获阶段,事件处理程序被调用的顺序是注册的顺序。
【问】如果在a3中取消阻止冒泡事件和捕获事件,点击c,会输出什么?
【答】a1
、a3
、a4
、b
、c1
、c2
、a2
- 不解释了,直接看图吧
【参考资料】 【MDN】EventTarget.addEventListener() 【掘金】你真的理解事件冒泡和事件捕获吗? - CodeFei 【掘金】JS中的事件委托或事件代理详解 - 慕容初晨 【知乎】JavaScript事件委托详解 - 技术杂谈 【简书】JavaScript阻止事件冒泡 - 一点红3340 JS阻止冒泡和取消默认事件(默认行为)