DOM事件流
- 事件流所描述的就是从页面中接受事件的顺序。
- DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
- 浏览器在为这个当前页面与用户做交互的过程中,比如我点击了这个鼠标左键,这个左键是怎么传到页面上。还有怎么响应的。事件流分三个阶段,第一阶段是捕获,第二阶段是目标阶段,比如点击的这个按钮,这个按钮就是目标阶段,事件通过捕获到达目标元素,就到达了目标阶段,第三个阶段是冒泡阶段,从目标元素再上传到window对象,就是冒泡的过程。
事件传播——冒泡与捕获
默认情况下,事件使用冒泡事件流,不使用捕获事件流。然而,在Firefox和Safari里,你可以显式的指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true。
冒泡事件流
事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),然后逐级传播到较为不具体的节点。在遵从W3C标准的浏览器里可以通过调用事件对象上的stopPropagation()方法,在Internet Explorer里可以通过设置事件对象的cancelBubble属性为true。如果不停止事件的传播,事件将一直通过DOM冒泡直至到达文档根。
DOM事件冒泡的具体流程:第一个接收的是目标元素——第二个接收的是...(子级--父级,按照html结构一层一层往上传)——然后接收的是body标签——html标签——document对象——最后一个接收的是window对象。
捕获事件流
事件的处理将从DOM层次的根开始,而不是从触发事件的目标元素开始,事件被从目标元素的所有祖先元素依次往下传递。在这个过程中,事件会被从文档根到事件目标元素之间各个继承派生的元素所捕获,如果事件监听器在被注册时设置了useCapture属性为true,那么它们可以被分派给这期间的任何元素以对事件做出处理;否则,事件会被接着传递给派生元素路径上的下一元素,直至目标元素。事件到达目标元素后,它会接着通过DOM节点再进行冒泡。
DOM事件捕获的具体流程:捕获是从上到下,具体第一个真正接收的是window(对象)——第二个接收的是document(对象)——第三个接收的是html标签(怎么获取html标签>document.documentElement)——第四个接收的是body(document.body)——......(父级--子级,剩下的就是按照普通的html结构一层一层往下传)——最后到达目标元素。
冒泡与捕获详解
以click点击事件为例。假如我们有一个多层结构标签。如下图,是4个div嵌套。每个div都有点击的监听事件,分别输出1234。当我们点击最里面的div时,点击事件开始传递,传递的全过程是1-2-3-4-4-3-2-1。
前半部分,事件从最外面的父div依次传递到最里面的后代div,1-2-3-4这部分我们叫捕获过程。
之后事件又从最里层的后代div逐层传出,4-3-2-1这部分我们叫冒泡过程。
如果我把捕获监听器和冒泡监听器都加上,如下图这样。
<div style="background: red;width: 240px;height: 240px" @click.capture="log(1)" @click="log(1)">
<div style="background: green;width: 200px;height: 200px" @click.capture="log(2)" @click="log(2)">
<div style="background: blue;width: 150px;height: 150px" @click.capture="log(3)" @click="log(3)">
<div style="background: black;width: 100px;height: 100px" @click.capture="log(4)" @click="log(4)">
</div>
</div>
</div>
</div>
methods: {
log (str) {
console.log(str)
},
}
更改代码如下
<div style="background: red;width: 240px;height: 240px" @click="log(1)">
<div style="background: green;width: 200px;height: 200px" @click.capture="log(2)">
<div style="background: blue;width: 150px;height: 150px" @click="log(3)">
<div style="background: black;width: 100px;height: 100px" @click.capture="log(4)">
</div>
</div>
</div>
</div>
将输出:2 4 3 1
阻止传递
在不使用任何框架的情况下,我们在js中通过stopPropagation方法阻止事件继续传递。 Vue框架使用stop修饰符来阻止事件传递。
<div style="background: red;width: 240px;height: 240px" @click.capture="log(1)" @click="log(1)">
<div style="background: green;width: 200px;height: 200px" @click.capture.stop="log(2)" @click="log(2)">
<div style="background: blue;width: 150px;height: 150px" @click.capture="log(3)" @click="log(3)">
<div style="background: black;width: 100px;height: 100px" @click.capture="log(4)" @click="log(4)">
</div>
</div>
</div>
</div>
将输出:1 2 后续由于事件传递被阻止,将不再触发