js中的捕获阶段和冒泡阶段
在 JavaScript 中,事件传播(Event Propagation)描述了当一个事件触发时,事件如何在 DOM 树中从触发元素(即事件的目标)向上传播或向下传播。
事件传播有两个主要阶段:捕获阶段(Capture Phase)和冒泡阶段(Bubble Phase)。
1. 捕获阶段(Capture Phase)
- 含义:事件从
document
元素开始,沿着 DOM 树向目标元素传播,直到触发事件的元素。也叫事件捕获阶段。 - 传播顺序:捕获阶段是从外层的元素到目标元素的过程。即,先触发文档级别的监听器,然后是父元素,直到目标元素。
事件捕获过程:
document -> html -> body -> ... -> targetElement
- 捕获阶段的作用是捕捉到事件并做出处理,通常可以对事件做一些预处理。
- 默认情况下,
addEventListener
的capture
选项是false
,即不启用捕获阶段。
2. 冒泡阶段(Bubble Phase)
- 含义:事件从触发的目标元素开始,沿着 DOM 树向上传播,直到
document
元素。也叫事件冒泡阶段。 - 传播顺序:冒泡阶段是从目标元素开始,逐层向上传播到根元素。
事件冒泡过程:
targetElement -> ... -> body -> html -> document
- 冒泡是事件传播的默认行为,它是大多数开发者所熟悉的事件传播方式。
- 事件会在目标元素被触发后,从目标元素向上传递,直到到达
document
。
捕获与冒泡的使用
addEventListener
方法可以通过第三个参数 capture
来控制事件监听器是在捕获阶段触发还是冒泡阶段触发。
控制传播阶段
- 捕获阶段(
capture: true
):监听器会在事件从根元素到目标元素的过程中触发。 - 冒泡阶段(
capture: false
):监听器会在事件从目标元素向上传播的过程中触发。
默认情况下,addEventListener
会在冒泡阶段触发事件(capture: false
)。要使事件在捕获阶段触发,可以将 capture
设置为 true
。
示例代码:
捕获阶段:
const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");// 捕获阶段监听器
parentElement.addEventListener("click", () => {console.log("捕获阶段: 父元素被点击");
}, true); // capture: truechildElement.addEventListener("click", () => {console.log("捕获阶段: 子元素被点击");
}, true); // capture: true
冒泡阶段:
const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");// 冒泡阶段监听器
parentElement.addEventListener("click", () => {console.log("冒泡阶段: 父元素被点击");
}, false); // 默认,冒泡阶段childElement.addEventListener("click", () => {console.log("冒泡阶段: 子元素被点击");
}, false); // 默认,冒泡阶段
输出:
-
如果点击了
childElement
:- 捕获阶段:
parentElement
→childElement
(按顺序) - 冒泡阶段:
childElement
→parentElement
(按顺序)
- 捕获阶段:
捕获与冒泡的关系
捕获和冒泡是事件传播的两个阶段,它们是独立的:
- 捕获阶段:从最外层的元素
document
开始到目标元素。 - 冒泡阶段:从目标元素开始到最外层
document
的元素。
通过事件监听器的 capture
选项,开发者可以选择在哪个阶段处理事件。
阻止事件传播
你可以通过 event.stopPropagation()
方法来阻止事件在捕获和冒泡阶段继续传播。
-
阻止捕获与冒泡:
event.stopPropagation();
-
阻止默认行为:比如阻止链接跳转:
event.preventDefault();