最近面试中有被问到EventTarget.addEventListener()方法的第三个参数useCapture(此方法就不着重讲解了,同时该方法的第三个参数可以传一个对象,可以参考mdn文档,讲解的很详细EventTarget.addEventListener() - Web API 接口参考 | MDN)
浏览器事件触发的三个阶段
捕获阶段:
事件从父节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到达到目标节点。
目标阶段:
事件到达目标节点时,就到了目标阶段,事件在目标节点上被触发
冒泡阶段:
事件在目标节点上触发后,不会终止,一层层向上冒,回溯到父节点
我们直接为元素绑定事件通过onxxx绑定和通过addEventListener添加绑定事件,默认都是在事件冒泡阶段执行事件函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box1{
width: 300px;
height: 300px;
background-color: red;
font-size:20px;
}
.box2{
width: 200px;
height: 200px;
background-color: rgb(0, 187, 255);
font-size:20px;
}
.box3{
width: 100px;
height: 100px;
background-color: orange;
font-size:20px;
}
</style>
</head>
<body>
<div class="box1">box1
<div class="box2">box2
<div class="box3">box3</div>
</div>
</div>
<script>
document.querySelector(".box1").onclick=()=>{
console.log("box1");
}
document.querySelector(".box2").onclick=()=>{
console.log("box2");
}
document.querySelector(".box3").onclick=()=>{
console.log("box3");
}
</script>
</body>
</html>
将绑定事件由onclick绑定改为addEventListener后结果与上图一致
// document.querySelector(".box1").onclick=()=>{
// console.log("box1");
// }
// document.querySelector(".box2").onclick=()=>{
// console.log("box2");
// }
// document.querySelector(".box3").onclick=()=>{
// console.log("box3");
// }
document.querySelector(".box1").addEventListener("click",()=>{
console.log("box1");
})
document.querySelector(".box2").addEventListener("click",()=>{
console.log("box2");
})
document.querySelector(".box3").addEventListener("click",()=>{
console.log("box3");
})
情况一:为.box1的addEventlistener添加第三个参数useCapture为true(默认是false)
document.querySelector(".box1").addEventListener("click",()=>{
console.log("box1");
},true)
document.querySelector(".box2").addEventListener("click",()=>{
console.log("box2");
})
document.querySelector(".box3").addEventListener("click",()=>{
console.log("box3");
})
此时我们会发现.box1元素绑定的事件回调是在我们捕获阶段触发的,而.box2和.box3触发的事件回调依旧是在我们冒泡阶段触发的
情况二:为.box2的addEventlistener添加第三个参数useCapture为true(默认是false)
document.querySelector(".box1").addEventListener("click",()=>{
console.log("box1");
})
document.querySelector(".box2").addEventListener("click",()=>{
console.log("box2");
},true)
document.querySelector(".box3").addEventListener("click",()=>{
console.log("box3");
})
同理,我们会发现,.box2是在事件捕获阶段触发的,而.box1和.box3都是在事件冒泡阶段触发的
情况三:为.box3的addEventlistener添加第三个参数useCapture为true(默认是false)
document.querySelector(".box1").addEventListener("click",()=>{
console.log("box1");
})
document.querySelector(".box2").addEventListener("click",()=>{
console.log("box2");
})
document.querySelector(".box3").addEventListener("click",()=>{
console.log("box3");
},true)
将.box3的useCapture改为true发现,执行的顺序与三个都不改变useCapture是一致的,这是因为当我们点击.box3的时候,我们从父节点(.box1)向.box3捕获的过程中,已经找到了event.target事件源了。