事件捕获
事件捕获模式流程:事件发生时,先触发目标元素的祖先元素的事件响应函数,然后触发其父元素的事件响应函数,并逐级到目标元素。
就是从外到内找监听函数,叫事件捕获
事件冒泡
事件冒泡模式流程正好与捕获模式相反,事件发生时,先触发目标元素的事件响应函数,再逐级追溯到其祖先元素。
从内到外找监听函数,叫事件冒泡。

DOM 事件流
DOM 事件流分为三个阶段:
- 事件捕获阶段 - 事件流由上往下直到目标元素
- 目标阶段 - 事件到达目标元素
- 事件冒泡阶段 - 事件流由下往上从目标元素直到最外层祖先元素
一般我们使用冒泡阶段的事件响应, addEventListener(event,handel) ,其实addEventListener还有第三个参数,如果需要指定捕获阶段的事件响应,设置第三个参数为true。
下面一个例子展示DOM事件流:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM事件流</title>
</head>
<body>
<div id="div1" style="border:1px solid #000;padding: 30px">
DIV1
<div id="div2" style="border:1px solid #000;padding: 30px">
DIV2
<div id="div3" style="border:1px solid #000; padding: 30px">DIV3</div>
</div>
</div>
</body>
<script type="text/javascript">
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
var div3 = document.getElementById('div3');
// true表示在捕获阶段处理事件、false表示在冒泡阶段处理
div1.addEventListener('click',function (event) {
console.log('事件捕获阶段: div1点击事件');
}, true);
div1.addEventListener('click',function () {
console.log('事件冒泡阶段: div1点击事件');
}, false);
div2.addEventListener('click',function () {
console.log('事件捕获阶段: div2点击事件');
}, true);
div2.addEventListener('click',function () {
console.log('事件冒泡阶段: div2点击事件');
}, false)
div3.addEventListener('click',function () {
console.log('事件捕获阶段: div3点击事件');
}, true);
div3.addEventListener('click',function () {
console.log('事件冒泡阶段: div3点击事件');
}, false)
</script>
</html>

在浏览器里执行,点击DIV3,可以看到控制台的输出:

一个特例
只有一个 div 被监听(不考虑父子同时被监听),fn 分别在捕获阶段和冒泡阶段监听click事件,用户点击的元素就是开发者监听的。
div.addEventListener('click',f1)
div.addEventListener('click',f2,true)
====> f1 先执行还是f2 先执行?
答:谁先监听谁先执行。
事件目标元素
e.target 和 this/e.currentTarget 的区别
e.target------目标元素,最直接引起事件的元素 / 用户操作的元素
this/e.currentTarget ----当前事件响应函数绑定的元素 / 开发者设置监听的元素
取消冒泡
捕获不可取消,但冒泡可以
e.stopPropagation() 可中断冒泡
有些事件也不可取消冒泡
具体MDN,如 MDN 搜索 sroll event,看到Bubbles和Cancelable
- Bubbles 表示事件是否冒泡
- Cancelable 表示是否可以取消冒泡
阻止滚动
scroll 事件不可取消冒泡
阻止 scroll 默认动作没有用,因为先有滚动才有滚动事件。
要阻止滚动,可以阻止 wheel 和 touch 的默认动作。
注意要找准滚动条所在元素
滚动条还能用,可用CSS设置滚动条width:0
::webkit-scroll {width:0 !important}
使用CSS设置 overflow:hidden 可以直接取消滚动条,但此时 JS 依旧可以修改scrollTop
自定义事件
示例
