JavaScript事件的传播
- 当某个元素触发一个事件的时候,其父元素也会触发相同的事件,父元素的父元素 也会触发相同的事件
- 子级标签绑定事件,父级标签也绑定相同类型的事件,
- 子级标签触发事件,父级标签也会触发绑定的类型相同的事件
- 这样的执行原理称为事件的传播 ,又叫:事件的冒泡或者冒泡事件
一、事件传播的方式
在讲事件传播的方式之前,首先讲一下 目标 的概念:
假设你点击了一个元素,那么这个元素就是事件的目标。
-
在旧版本的浏览器中,事件的传播有 2种方式
1、捕获
- 从 父级 => 子级 执行程序
- 也即: 从 外 至 内
- 就是从 window 的事件处理函数开始,依次向内,直到事件 目标 的事件处理函数执行
2、冒泡
- 从 子级 => 父级 执行程序
- 也即: 从 内 至 外
- 就是从事件 目标 的事件处理函数开始,依次向外,直到 window 的事件处理函数触发。
-
新版本浏览器 默认 都是以 冒泡方式 执行事件的传播
-
给事件监听语法的第三个参数定义为 true,事件传播会按照捕获方式执行
语法:元素.addEventListener('事件类型', 事件处理函数, 冒泡还是捕获)
false:默认,冒泡
true:捕获
二、事件传播的阻止
有些时候,我们并不想事件传播给父级的元素,这时就需要阻止事件的传播。
事件传播的阻止需要考虑浏览器的兼容:
-
标准浏览器
事件对象.stopPropagation();
-
低版本IE浏览器
事件对象.cancelBubble = true;
三、事件传播案例
接下来通过一个案例来更好的了解一下事件的传播
<!DOCTYPE html>
<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>
div {
width: 800px;
height: 800px;
background: pink;
margin: 50px auto;
display: flex;
justify-content: center;
align-items: center;
}
h1 {
width: 600px;
height: 600px;
background: orange;
display: flex;
justify-content: center;
align-items: center;
}
p {
width: 400px;
height: 400px;
background: skyblue;
}
</style>
</head>
<body>
<div>
<h1>
<p></p>
</h1>
</div>
<script>
var oDiv = document.querySelector('div');
var oH1 = document.querySelector('h1');
var oP = document.querySelector('p');
var tBody = document.querySelector('body');
var tHtml = document.querySelector('html');
oDiv.addEventListener('click', function (e) {
// 阻止事件的传播
// e.stopPropagation();
console.log('您点击的是div标签');
})
oH1.addEventListener('click', function (e) {
// 阻止事件的传播
// e.stopPropagation();
console.log('您点击的是h1标签');
})
oP.addEventListener('click', function (e) {
// 阻止事件的传播
// e.stopPropagation();
console.log('您点击的是p标签');
})
tBody.addEventListener('click', function (e) {
console.log('您点击的是body标签');
})
tHtml.addEventListener('click', function (e) {
console.log('您点击的是html标签');
})
document.addEventListener('click', function (e) {
console.log('您点击的是document标签');
})
window.addEventListener('click', function (e) {
console.log('您点击的是window标签');
})
</script>
</body>
</html>
1、上例中没有阻止事件的传播,点击<p>
的时候,会依次触发<p>
的点击事件、<h1>
的点击事件、<div>
的点击事件、<body>
的点击事件、<html>
的点击事件、document
的点击事件、 window
的点击事件。
控制台会依次输出:
您点击的是p标签
您点击的是h1标签
您点击的是div标签
您点击的是body标签
您点击的是html标签
您点击的是document标签
您点击的是window标签
- 也就是说,页面上任何一个元素触发事件,都会从这个元素开始,一层一层的向父级传播事件,最终导致 window 的相同事件触发。前提是各层级元素得有注册相同的事件,不然不会触发。
2、在事件传播的过程中,有一些注意的点:
-
只会传播同类事件
-
只会从点击元素开始,按照 html 的结构,逐层向上触发父级元素的事件
-
内部元素不管有没有该事件,只要上层元素有该事件,那么上层元素的事件就会被触发
-
意思就是:如果把上例中
<p>
的点击事件代码删除,那么点击<p>
的时候也会触发它的父级的点击事件,控制台会依次输出:-
您点击的是h1标签
-
您点击的是div标签
-
您点击的是body标签
-
您点击的是html标签
-
您点击的是document标签
-
您点击的是window标签
-
-
3、最后思考一个问题
事件会从自己开始,通过传播,直到 window 的所有相同事件都被触发;是因为我们点在自己身上,也逐层的点在了直至 window 的每一个元素身上,但是到底是先点在自己身上,还是先点在了window 身上呢?
先说结论:
- 先点在自己身上,就是先执行自己的事件处理函数,逐层向上最后执行 window 的事件处理函数
- 反之,则是先执行 window 的事件处理函数,逐层向下最后执行自己身上的事件处理函数
通过上例我们发现,点击<p>
的时候,是先执行<p>
的事件处理函数,再依次向上执行它父级的事件处理函数.
所以答案就是:先点在了自己身上。