下午学习Dom事件流,为了更深入的理解由于事件冒泡导致的mouseover和mouseenter的区别,进行了测试,特此记录。
1.Dom事件流
所谓Dom事件流,指事件流描述 页面接收事件的顺序,也就是事件发生后的一定执行顺序。具体分为三个阶段:
|-捕获阶段:
|-目标阶段:
|-冒泡阶段:
用具体代码来解释上述阶段的含义:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dom事件流</title>
<style>
.fa {
height: 100px;
width: 100px;
background-color: skyblue;
}
.son {
height: 50px;
width: 50px;
background-color: pink;
}
</style>
</head>
<body>
<div class="fa">
<div class="son"></div>
</div>
<script>
var fa = document.querySelector('.fa');
var son = document.querySelector('.son');
fa.addEventListener('click', function() {
console.log('冒泡 fa');
}, false);
fa.addEventListener('click', function() {
console.log('捕获 fa');
}, true);
son.addEventListener('click', function() {
console.log('冒泡 son');
}, false);
son.addEventListener('click', function() {
console.log('捕获 son');
}, true);
document.addEventListener('click', function() {
console.log('冒泡 document');
}, false);
document.addEventListener('click', function() {
console.log('捕获 document');
}, true);
</script>
</body>
</html>
先看运行结果:
先点击蓝色区域,输出如下
再点击粉色区域,也就是子元素部分,输出如下
也就是说,在该段代码中,点击了哪个元素,谁就是目标元素。
从运行结果可以看出,事件流的总体执行顺序为先捕获,后冒泡。
捕获过程的先后顺序为:document->html->body->fa->son
冒泡过程为捕获的逆序:son->fa->body->html->document
但是我们发现有一个特殊点,就是先输出冒泡son 后输出捕获son,因为对于目标元素来说,先捕获还是先冒泡完全要按照目标元素捕获和冒泡在代码中的顺序,谁在前就要先执行谁。
那么如何从代码中区别事件冒泡还是捕获呢?事实上,不同点就在于addEventListener()的第三个参数,当第三个参数为false(可省略),事件冒泡。当第三个参数为true,事件捕获。
//冒泡事件
son.addEventListener('click', function() {
console.log('冒泡 son');
}, false);
//捕获事件
son.addEventListener('click', function() {
console.log('捕获 son');
}, true);
所以回过头来再分析上面的代码:当点击子元素时,先输出捕获document->捕获父级div fa->接下来对于目标元素的子级div son因为在代码中冒泡事件在前,所以要先输出冒泡 son->后输出捕获son->目标元素之后整体开始捕获 即输出 冒泡fa->冒泡document
那么我们再来验证一下:
<style>
.fa {
height: 100px;
width: 100px;
background-color: skyblue;
}
</style>
<body>
<div class="fa"></div>
<script>
var fa = document.querySelector('.fa');
fa.addEventListener('click', function() {
console.log('冒泡 fa');
}, false);
fa.addEventListener('click', function() {
console.log('捕获 fa');
}, true);
document.addEventListener('click', function() {
console.log('冒泡 document');
}, false);
document.addEventListener('click', function() {
console.log('捕获 document');
}, true);
//
</script>
</body>
运行结果:
<script>
var fa = document.querySelector('.fa');
fa.addEventListener('click', function() {
console.log('捕获 fa');
}, true);
fa.addEventListener('click', function() {
console.log('冒泡 fa');
}, false);
document.addEventListener('click', function() {
console.log('冒泡 document');
}, false);
document.addEventListener('click', function() {
console.log('捕获 document');
}, true);
//
</script>
运行结果
需要注意的是,并不是所以的事件都有捕获和冒泡的
如:onfocus、onblur、onmouseenter、onmouseleaver
举例onmouseenter和onmouseover进一步测试对于有冒泡和没有冒泡事件的不同。代码如下:大家可以将代码粘贴到本地自行演示来体会
<!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>
.fa {
height: 200px;
width: 200px;
background-color: pink;
}
.son {
height: 100px;
width: 100px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="fa">
<div class="son"></div>
</div>
<script>
var fa = document.querySelector('.fa');
var son = document.querySelector('.son');
fa.addEventListener('mouseover', function() {
console.log('mouseover');
});
fa.addEventListener('mouseenter', function() {
console.log('mouseenter');
});
</script>
</body>
</html>
运行结果:
对于mouseover事件
|-鼠标移动到父元素粉色区域会输出“mouseover”。
|-鼠标移动到子元素粉色区域会输出“mouseover”,存在冒泡事件。
|-鼠标从父元素移动到子元素时,由于冒泡事件的存在,会输出“mouseover”。
|-当鼠标从子元素移动到父元素时,也会输出“mouseover”
对于mouseenter事件
|-当鼠标经过父元素会输出"mouseenter"
|-鼠标经过子元素也会输出"mouseenter",因为子盒子在父亲范围内,子元素占用父元素范围,所以鼠标经过子元素,相当于触发了父元素事件。
|-鼠标从父元素移动到子元素没有反应,不会输出"mouseenter"。因为对于mouseenter事件,不会冒泡传递,所以并不会触发父元素事件
|-鼠标从子元素移动到父元素没有反应,不会输出"mouseenter"。因为从整体来说鼠标一直都在父元素的范围内移动,并没有移动到其他地方,所以不会触发父元素的mouseenter事件。
总结mouseover和mouseenter的区别:
mouseover鼠标经过自身盒子会触发,经过子盒子还会触发,原因是mouseover发生冒泡事件
mouseenter只经过自己才会触发,mouseenter不会冒泡