1. 捕获阶段实现 + 阻止事件流传播 + 阻止元素默认行为
默认只在冒泡阶段触发事件。可以选择不在冒泡阶段触发事件,而在捕获阶段触发事件。语法: 元素对象.addEventListener('事件类型', 要执行的函数, 是否在捕获阶段触发事件)
,是否在捕获阶段触发事件默认为false。L0旧版事件监听只有冒泡,没有监听
示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
<title>Title</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: purple;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
document.addEventListener('click', function (e) {
alert('我是爷爷')
// e.stopPropagation()
// e.preventDefault()
}, true)
const father = document.querySelector('.father')
father.addEventListener('click', function () {
alert('我是爸爸')
}, true)
const son = document.querySelector('.son')
son.addEventListener('click', function (e) {
alert('我是儿子')
// e.stopPropagation()
// e.preventDefault()
}, true)
</script>
</body>
</html>
如下。点击紫色的小盒子,先弹出我是爷爷,再弹出我是爸爸,最后弹出我是儿子
如果addEventListener的第三个参数都是false(默认),则点击紫色的小盒子,先弹出我是儿子,再弹出我是爸爸,最后弹出我是爷爷
阻止事件流传播:
- 捕获阶段:可以在爷爷的事件监听函数中,添加
e.stopPropagation()
。这样点击紫色的小盒子,只弹出我是爷爷 - 冒泡阶段:可以在儿子的事件监听函数中,添加
e.stopPropagation()
。这样点击紫色的小盒子,只弹出我是儿子
阻止默认行为:
可以使用e.preventDefault()
来阻止元素的默认行为。如:
- 在a链接的监听事件中,阻止链接的跳转
- form表单的监听事件中,阻止表单域跳转
2. mouseover/mouseout和mouseenter/mouseleave的区别
- mouseover: 鼠标进入该元素、或鼠标从子元素进入该元素、或鼠标从该元素进入子元素(子元素事件流冒泡),都会触发事件
- mouseout: 鼠标离开该元素、或鼠标离开该元素进入子元素、或鼠标离开子元素进入该元素(子元素事件流冒泡),都会触发事件
- mouseenter: 只有鼠标进入该元素,会触发事件
- mouseleave: 只有鼠标离开该元素,会触发事件
示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
<title>Title</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: purple;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
const father = document.querySelector('.father')
const son = document.querySelector('.son')
father.addEventListener('mouseover', function () {
console.log('鼠标进入父亲')
})
father.addEventListener('mouseout', function () {
console.log('鼠标离开父亲')
})
</script>
</body>
</html>
mouseover和mouseout效果如下:
- 鼠标移入粉色的大盒子,控制台打印【鼠标进入父亲】
- 鼠标从粉色的大盒子移入紫色的小盒子,先打印【鼠标离开父亲】,再打印【鼠标进入父亲】
- 鼠标从紫色的小盒子移入粉色的大盒子,先打印【鼠标离开父亲】,再打印【鼠标进入父亲】
- 鼠标移出粉色的大盒子,控制台打印【鼠标离开父亲】
将html文件中的mouseover改成mouseenter,mouseout改成mouseleave的效果如下: - 鼠标移入粉色的大盒子,控制台打印【鼠标进入父亲】
- 鼠标从粉色的大盒子移入紫色的小盒子,无消息打印
- 鼠标从紫色的小盒子移入粉色的大盒子,无消息打印
- 鼠标移出粉色的大盒子,控制台打印【鼠标离开父亲】
3. 事件委托
如果ul下面有2个li,我们想给每个li绑定相同的点击事件。以前我们都是通过for循环给每个li绑定监听事件,这样效率非常低
可以只给li的父亲 ul绑定点击事件,当点击其中一个li的时候,默认会冒泡触发ul的点击事件。然后通过e.taget
获取到点击的这个li,对这个li的样式进行改变
所以将所有的事件监听,都委托给元素的父亲进行监听,就是事件委托
示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
<title>Title</title>
</head>
<body>
<ul>
<li>第1个孩子</li>
<li>第2个孩子</li>
<p>我不需要改变颜色</p>
</ul>
<script>
const ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
// 只有li才改变颜色
if (e.target.tagName === 'LI') {
e.target.style.color = 'red'
}
})
</script>
</body>
</html>
如下所示。点击第一个li会变成红色,点击p不会变色