👉 彻底弄懂js中事件冒泡和捕获是怎么回事
一、DOM事件触发经历的三个阶段
1、首先我们要弄清楚当一个dom事件被触发时,它不仅仅只是单纯地在自身对象上触发一次,而是经历了三个不同的阶段:👇
捕获阶段:先由文档的根节点document往事件触发对象,从外向内捕获事件对象;
目标阶段:到达目标事件位置,触发事件;
冒泡阶段:再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象。
2、下面贴上一张 w3c解释事件流 的图:
二、冒泡和捕获
1、当我们注册一个事件时,事件默认使用冒泡事件流,不使用捕获事件流。
element.addEventListener(event, function, useCapture)
event: 必须。字符串,指定事件类型。
function: 必须。指定要事件触发时执行的函数。
useCapture: 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。false为冒泡(默认),true为捕获。
2、下面在代码中验证,直接附上全部代码。(可以粘到自己编辑器中运行、尝试一下)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>event</title>
<style>
#one{
width: 600px;
height: 600px;
background-color: green;
}
#two{
width: 400px;
height: 400px;
background-color: yellow;
}
#three{
width: 200px;
height: 200px;
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="one">one
<div id="two">two
<div id="three">three</div>
</div>
</div>
<script>
var one = document.getElementById('one'),
two = document.getElementById('two'),
three = document.getElementById('three');
one.addEventListener('click', function(){
console.log('one捕获')
}, true)
two.addEventListener('click', function(){
console.log('two捕获')
}, true)
three.addEventListener('click', function(){
console.log('three捕获')
}, true)
one.addEventListener('click', function(){
console.log('one冒泡')
}, false)
two.addEventListener('click', function(){
console.log('two冒泡')
}, false)
three.addEventListener('click', function(){
console.log('three冒泡')
}, false)
</script>
</body>
</html>
3、当我们点击three时,可以看到确实是先由外向内事件捕获,一直到事发元素,再由内向外冒泡到根节点上。
4、如果一个元素既注册了冒泡事件,也注册了捕获事件,则按照注册顺序执行。
我们修改代码把冒泡事件放在捕获事件之前:
one.addEventListener('click', function(){
console.log('one冒泡')
}, false)
two.addEventListener('click', function(){
console.log('two冒泡')
}, false)
three.addEventListener('click', function(){
console.log('three冒泡')
}, false)
one.addEventListener('click', function(){
console.log('one捕获')
}, true)
two.addEventListener('click', function(){
console.log('two捕获')
}, true)
three.addEventListener('click', function(){
console.log('three捕获')
}, true)
再点击three,可以看到这次three先是执行冒泡后捕获的,由此可见一个元素同时注册了冒泡和捕获事件,则会按照注册顺序执行。
三、阻止事件冒泡
1、在很多时候我们并不需要元素绑定的事件向外冒泡,这时我们就要阻止事件的冒泡。
阻止冒泡:w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true;
我们再次修改代码,阻止three的事件冒泡:
three.addEventListener('click', function(){
console.log('three冒泡')
var e = e || window.event; // firefox下window.event为null, IE下event为null
// 阻止冒泡
if(e.stopPropagation){
e.stopPropagation() //其他浏览器
}else{
e.cancelBubble = true //IE浏览器
}
}, false)
修改完代码后我们再次点击three,可以看到three的点击事件触发后就停止继续向外冒泡了;