# 什么是事件流
JS
和HTML
之间的交互是通过事件来完成的,我想让页面动起来,就要通过给 DOM
绑定事件来实现,而事件就是文档或浏览器窗口发生的一些特定的交互瞬间
事件流表示的就是事件接收和传播的过程,说白点就是一个事件发生的顺序
事件机制描述的是事件在
DOM
里面的传递顺序,以及我们可以对这些事件做出如何的响应
三个阶段:
- 事件捕获阶段:事件从根节点从外向内往目标节点传播的阶段
- 目标阶段:真正的目标节点正在处理事件的阶段
- 事件冒泡阶段:事件从目标节点从内向外到根节点传播的阶段
这篇文章就来分析一下事件捕获和事件冒泡的原理
# 事件捕获
event capturing
—— 重点就是从外向内传播事件
我们直接看下面这个例子👇
部分代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="box1">
box1
<div id="box2">
box2
<button id="child">点我测试</button>
</div>
</div>
</body>
</html>
<script>
window.addEventListener(
"click",
() => {
console.log("Window触发了");
},
true
);
document.addEventListener(
"click",
() => {
console.log("Document触发了");
},
true
);
document.querySelector("#box2").addEventListener(
"click",
() => {
console.log("box2触发了");
},
true
);
document.querySelector("#box1").addEventListener(
"click",
() => {
console.log("box1触发了");
},
true
);
document.querySelector("#child").addEventListener(
"click",
() => {
console.log("点击了button");
},
true
);
</script>
点击button,输出上面的结果
在这里我们使用了addEventListener
方法来操作,需要注意的是第三个参数默认是false
,表示在事件冒泡阶段调用事件处理函数,这里我们想让他们按照事件捕获阶段来输出,需要手动设置为true
通过结果我们可以看到,事件处理顺序是 Window -> Document -> box1 -> box2 -> child
而且需要注意的是,如果child
还有子元素,那我们点击child
,触发事件捕获的过程是不会传播到子元素上的
# 事件冒泡
同样的例子,我们修改addEventListener
第三个参数为false,或者直接不写,默认就是false
,我们来看一下事件冒泡的执行顺序结果
可以看到输出的顺序正好和事件捕获相反了 👇
child -> box2 -> box1 -> Document -> Window
# 阻止事件冒泡
看到这里,其实我们就会想到一个需求了,addEventListener
默认是事件冒泡,那在我们点击子元素时,由于事件冒泡,父元素上绑定的事件也会一并触发,怎么解决这个问题呢?
我们可以通过stopPropagation()
来解决这个需求,它会阻止事件向上或向下传播,相当于让事件传播在此刻停止,但绑定了该方法的事件仍会触发
还是上边的例子,我们在box2
上设置stopPropagation()
document.querySelector("#box2").addEventListener("click", (e) => {
console.log("box2触发了");
e.stopPropagation();
});
可以看到box2
上的事件触发之后,不会再继续向外传播了
- 在
W3C
中,使用stopPropagation()
方法 - 在
IE
下设置cancelBubble = true
如果想要阻止事件的默认行为,比如点击<a>
标签后的跳转
- 在
W3c
中,使用preventDefault()
方法 - 在
IE
下设置window.event.returnValue = false
# 总结
以前,Netscape
和Microsoft
是不同的事件传播方式
Netscape
中,div
先触发,也就是事件捕获先触发Microsoft
中,p
先触发,也就是事件冒泡先触发
两种事件处理顺序刚好相反。IE
只支持事件冒泡,Mozilla, Opera 7
和 Konqueror
两种都支持事件流,旧版本的 Opera's
和 iCab
两种都不支持
现在,W3C
规范统一了这个顺序,任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达了事件源元素。然后,再从事件源往上进行事件冒泡,直到到达document
这也对应了事件流的三个阶段,先是事件捕获阶段,然后是目标阶段,最后是事件冒泡阶段
最后,还要注意的是,不是所有的事件都能冒泡,比如blur、focus、load、unload
等等,(这个也是从别人的文章里摘过来的,在这里就不进一步测试了~ )。