事件模型
一、DOM标准规定,事件发生的过程,要遵循事件模型: 3个阶段
- 捕获: 从根节点document开始,由外向内,依次遍历实际点击的元素的各级父元素。并记录各级父元素上是否绑定了单击事件。——只记录,不执行
- 目标触发:优先触发实际点击的目标元素上绑定的事件处理函数 目标元素(target): 实际想点击的那个元素
- 冒泡: 由内向外,按捕获阶段的反向,依次触发各级父元素上的事件处理函数。
二、事件的冒泡
如图,点击最内层的块时,会触发外层所有的click事件
事件触发顺序是由内到外的,这就是事件冒泡。如果点击子元素不想触发父元素的事件,可使用event.stopPropagation()方法
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.d1 .d2 .d3 {
cursor: pointer;
}
.d1 {
width: 300px;
height: 300px;
background: red;
position: relative;
}
.d2 {
width: 200px;
height: 200px;
background: green;
position: absolute;
top: 50px;
left: 50px;
}
.d3 {
width: 100px;
height: 100px;
background: blue;
position: absolute;
top: 50px;
left: 50px;
}
</style>
</head>
<body>
<div id="root">
<div class="d1">
<div class="d2">
<div class="d3"></div>
</div>
</div>
</div>
</body>
<script>
let d1 = document.getElementsByClassName("d1")[0];
let d2 = document.getElementsByClassName("d2")[0];
let d3 = document.getElementsByClassName("d3")[0];
//绑定事件
d1.onclick = function (e) {
e.stopPropagation();
console.log("点到D1了!");
};
d2.onclick = function (e) {
e.stopPropagation();
console.log("点到D2了!");
};
d3.onclick = function (e) {
e.stopPropagation();
console.log("点到D3了!");
};
</script>
</html>
复制代码
三、事件的捕获
还是上面的图,这次用addEventListener(event, function, useCapture)来校验
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.d1 .d2 .d3 {
cursor: pointer;
}
.d1 {
width: 300px;
height: 300px;
background: red;
position: relative;
}
.d2 {
width: 200px;
height: 200px;
background: green;
position: absolute;
top: 50px;
left: 50px;
}
.d3 {
width: 100px;
height: 100px;
background: blue;
position: absolute;
top: 50px;
left: 50px;
}
</style>
</head>
<body>
<div id="root">
<div class="d1">
1
<div class="d2">
2
<div class="d3">3</div>
</div>
</div>
</div>
</body>
<script>
let d1 = document.getElementsByClassName("d1")[0];
let d2 = document.getElementsByClassName("d2")[0];
let d3 = document.getElementsByClassName("d3")[0];
//绑定事件
//addEventListener(event, function, useCapture)
//addEventListener(绑定的事件, 执行的函数, '参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数')
d1.addEventListener(
"click",
function () {
console.log("d1被点击了!");
},
true
);
d2.addEventListener(
"click",
function (e) {
console.log("d2被点击了!");
},
true
);
d3.addEventListener(
"click",
function () {
console.log("d3被点击了!");
},
true
);
</script>
</html>
复制代码
当点击最内层的块的时候,我们可以看到控制台打印的顺序是由外到内 和事件的冒泡顺序恰恰相反
四、事件委托(事件代理)
说白了就是相同的事件,绑定在最外层的元素上。让最外层的元素,帮内层的元素触发事件,也就是事件的代理(委托)。然后可以通过event.target去获取到事件源,能够减少监听事件,提升性能。
如图 只给最外层的ul绑定了事件,但是点击星期三时,就能触发事件,打印我们想要的结果。
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul class="day">
<li>星期一</li>
<li>星期二</li>
<li>星期三</li>
<li>星期四</li>
<li>星期五</li>
</ul>
</body>
<script>
let day = document.getElementsByClassName("day")[0];
day.onclick = function (e) {
console.log(e.target.innerText);
};
</script>
</html>