前情提要
讲到Dom的事件流可能第一时间想到的便是事件冒泡和事件捕获。准确的说Dom事件流分为三个阶段:第一个是事件捕获阶段,通过dom节点由父到子的顺序找到事件的触发点也就是第二个阶段:处于目标阶段。最后是事件冒泡阶段,通过由子到父的顺序将事件触发依次通知下去。
Dom事件流中的事件冒泡和事件捕获的过程叫事件传播
而执行顺序与其三个阶段是一样的,当有事件被触发时,会先通过事件传播从html根标签开始一级一级向内部去找到事件的触发节点。然后就是处于目标阶段。最后事件触发的节点再从其向html根标签一级一级的通过事件传播进行冒泡,也就是事件冒泡阶段。
可能对于事件冒泡和事件循环很多jym都知道,但是没有具体的玩过。所以,今天就从代码的执行来具体看看执行过程。
dom.addEventListener
在从代码看事件循环前,咱们还得简单的介绍下咱们的好朋友addEventListener,也就是事件注册。dom绑定点击事件有两种方式,第一种就是直接在dom上写onClick,然后绑定方法。第二种就是通过事件注册也就是addEventListener,它可以帮我们不用在dom上写任何代码就能实现绑定点击事件。 而它会接收三个参数:
第一个参数是注册什么事件,比如click事件,或者change事件等
第二个参数接收一个方法,当事件被触发时就会执行
第三个参数我们很少用到,接收一个boolean值。默认为false。
为false时事件的方法会在事件冒泡阶段执行
为true时事件的方法会在事件捕获阶段执行
代码执行
// 事件捕获<div id="container"><div id="parent"><button id="child">点我</button></div></div><script>var containerDom = document.getElementById('container');var parentDom = document.getElementById('parent');var childDom = document.getElementById('child');function containerCapture() {console.log('我是容器-捕获')}function parentCapture() {console.log('我是父节点-捕获')}function childCapture() {console.log('我是子节点-捕获')}containerDom.addEventListener('click', containerCapture, true)parentDom.addEventListener('click', parentCapture, true)childDom.addEventListener('click', childCapture, true)</script>// 打印结果我是容器-捕获我是父节点-捕获我是子节点-捕获// 事件冒泡var containerDom = document.getElementById('container');var parentDom = document.getElementById('parent');var childDom = document.getElementById('child');function containerBubbling() {console.log('我是容器-冒泡')}function parentBubbling() {console.log('我是父节点-冒泡')}function childBubbling() {console.log('我是子节点-冒泡')}containerDom.addEventListener('click', containerBubbling)parentDom.addEventListener('click', parentBubbling)childDom.addEventListener('click', childBubbling)// 打印结果我是子节点-冒泡我是父节点-冒泡我是容器-冒泡
补充知识点
dom事件流中的事件冒泡让我们是又爱又恨。假如我们同时在子节点和父节点上绑定了相同的事件后,子节点的事件触发后父节点的也会触发。这很显然不是我们想要的。
此时我们可以用:event.stopPropagation来阻止事件冒泡。
我们还可以使用:event.preventDefault来阻止默认事件。比如a标签的跳转等。
我们还可以在回调函数中直接return false;来同时阻止事件冒泡和阻止默认事件。
在vue中可以使用@click.stop=""来阻止事件冒泡。
而对于事件冒泡的应用我还可以通过事件代理来优化js的性能。
还有个重中之重:当事件不需要的时候记得使用removeEventListener来移除事件句柄。
下一篇写事件代理,又称事件委托。
原文:https://juejin.cn/post/7101667955284393992