持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
前情提要
- 讲到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来移除事件句柄。
- 下一篇写事件代理,又称事件委托。