事件完整执行过程中的流动路径。包含事件捕获和事件冒泡两个阶段
从 DOM 根元素开始执行对应事件。
addEventListener(type, listener, useCapture)。useCapture 默认为 false(冒泡阶段触发),useCapture 设置为 true(捕获阶段触发)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>事件捕获</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: skyblue;
}
.son {
width: 100px;
height: 100px;
background-color: orange;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
const father = document.querySelector('.father')
const son = document.querySelector('.son')
father.addEventListener(
'click',
function () {
console.log('father...')
},
// 捕获阶段触发
true
)
son.addEventListener(
'click',
function () {
console.log('son...')
},
true
)
</script>
</body>
</html>
如上:点击 son 对应的 div,从外到里依次执行 father->son 对应的 click 事件回调函数
当一个元素触发事件后,依次向上执行所有父级元素对应的同名事件。事件冒泡默认存在。
addEventListener(type, listener, useCapture)。useCapture 默认为 false(冒泡阶段触发),沿着 DOM 树向上冒泡的事件会触发事件回调函数。
...
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
const father = document.querySelector('.father')
const son = document.querySelector('.son')
father.addEventListener('click', function () {
console.log('father...')
})
son.addEventListener('click', function () {
console.log('son...')
})
</script>
</body>
</html>
如上:点击 son 对应的 div,从里到外依次执行 son->father 对应的 click 事件回调函数
stopPropagation:阻止事件传播
事件冒泡默认存在,在某些场景,导致父级元素受到影响。
使用"事件对象.stopPropagation()"来阻止事件传播(阻止事件捕获和事件冒泡),把事件限制在当前元素内
...
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
const father = document.querySelector('.father')
const son = document.querySelector('.son')
father.addEventListener('click', function () {
console.log('father...')
})
son.addEventListener('click', function () {
console.log('son...')
// 阻止事件传播
e.stopPropagation()
})
</script>
</body>
</html>
如上:点击 son 对应的 div,只执行 son 的 click 事件的回调函数
利用事件冒泡的特点,给父元素设置事件,当子元素触发事件时,冒泡到父元素,触发父元素的事件。
减少事件注册次数,提高程序性能。
...
<div class="tab-nav">
<ul>
<li><a class="active" href="#">精选</a></li>
<li><a href="#">美食</a></li>
<li><a href="#">百货</a></li>
<li><a href="#">个护</a></li>
<li><a href="#">预告</a></li>
</ul>
</div>
<script>
// 1、给tab栏绑定点击事件
// const as = document.querySelectorAll('.tab-nav li a')
// for (let i = 0; i < as.length; i++) {
// as[i].addEventListener('click', function () {
// document.querySelector('.tab-nav .active').classList.remove('active')
// document
// .querySelector(`.tab-nav li:nth-child(${i + 1}) a`)
// .classList.add('active')
// })
// }
// 2、利用事件委托的方式给父元素添加事件
const ul = document.querySelector('.tab-nav ul')
ul.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
document.querySelector('.tab-nav .active').classList.remove('active')
e.target.classList.add('active')
}
})
</script>
...
第一种方式循环遍历 li 元素给每一个 li 注册事件;第二种利用事件委托给父元素 ul 添加事件,当点击 li 里面的 a 标签时冒泡到父元素,触发父元素的点击事件。(通过"事件对象.target.tagName"来获得触发事件的元素)
记录学习JavaScript遇到的一些难点(学习途径:B站黑马程序员JavaScript视频,MDN)