之前对JS的事件流没有认真的去研究过,现在想好好记录下JS事件流的执行顺序。在介绍事件流之前先介绍一下DOM事件的分类。
DOM事件的分类
DOM事件分为:
- DOM0级事件
- DOM2级事件
DOM0级事件的注册:
// 直接在HTML标签中注册
<div onclick="clickHandler"></div>
<script>
function clickHandler(e) {
console.log('我是DOM0级事件');
}
</script>
// 在JS中直接定义在dom对象上
<div id="js-opera"></div>
<script>
const dom = document.querySelector('#js-opera');
dom.onclick = function(e) {
console.log('我是DOM0级事件');
}
</script>
DOM2级事件的注册
<div id="js-opera"></div>
<script>
// 通过addEventListener注册
const dom = document.querySelector('#js-opera');
function clickHanlder() {
console.log('我是DOM2级事件');
}
dom.addEventListener('click', clickHanlder);
</script>
事件流
事件流有两种形式:
捕获: 从上到下冒泡: 从下到上
执行顺序
事件的执行顺序是:捕获阶段 -> 目标阶段 -> 冒泡阶段;如下所示:

那么什么样的事件是捕获事件,什么样的事件是冒泡事件呢?还记得开始说的事件分类吗?对于DOM0级事件我们可以把它认为是在冒泡阶段执行的,对于DOM2级事件(addEventListener)定义时有3个参数:
- 第一个参数:事件名,如click、mousemove
- 第二个参数:回调函数
- 第三个参数:事件流类型,true | false,默认为false
- true: 代表捕获事件
- false: 代表冒泡事件
所以事件的执行顺序是先从上执行父级的捕获事件(如果有的话),所有父级的捕获事件执行完之后在执行触发事件的dom元素绑定的相关事件,最后在从目标元素从下往上执行冒泡事件。
目标阶段事件执行的顺序
捕获阶段和冒泡阶段事件的执行顺序很好理解,那么对于目标阶段呢?目标阶段的dom元素可能定义了捕获事件、冒泡事件|DOM0级事件。对于目标阶段执行事件的顺序是不管冒泡还是捕获的,执行顺序是根据事件在js中定义的顺序来的。
实践
接下来我们来举例验证一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>事件流</title>
<style>
.fd-deep-1 {
text-align: center;
width: 200px;
height: 100px;
border: 1px solid #cecece;
margin: 0 auto;
cursor: pointer;
}
.fd-deep-2 {
text-align: center;
width: 150px;
height: 75px;
border: 1px solid #cecece;
margin: 0 auto;
cursor: pointer;
}
.fd-deep-3 {
text-align: center;
width: 100px;
height: 50px;
border: 1px solid #cecece;
margin: 0 auto;
cursor: pointer;
}
</style>
</head>
<body>
<div class="fd-deep-1" onclick="clickHandler('deep-1')">
deep-1
<div class="fd-deep-2" onclick="clickHandler('deep-2')">
deep-2
<div class="fd-deep-3" onclick="clickHandler('deep-3')">deep-3</div>
</div>
</div>
<script>
function clickHandler(param) {
console.log(param);
}
function getDom(className) {
return document.querySelector(`.${className}`);
}
const deep1 = getDom('fd-deep-1');
const deep2 = getDom('fd-deep-2');
const deep3 = getDom('fd-deep-3');
deep1.addEventListener('click', function() {console.log('deep1冒泡')});
deep1.addEventListener('click', function() {console.log('deep1捕获')}, true);
deep2.addEventListener('click', function() {console.log('deep2冒泡')});
deep2.addEventListener('click', function() {console.log('deep2捕获')}, true);
deep3.addEventListener('click', function() {console.log('deep3冒泡')});
deep3.addEventListener('click', function() {console.log('deep3捕获')}, true);
</script>
</body>
</html>
输出结果为:
deep1捕获
deep2捕获
deep-3
deep3冒泡
deep3捕获
deep-2
deep2冒泡
deep-1
deep1冒泡