在 javascript 事件捕获与冒泡中,window 和 document 的执行顺序由 dom 规范严格定义:先 window 的捕获阶段,再 document 的捕获阶段,接着目标节点自身(先捕获后冒泡),然后 document 的冒泡阶段,最后 window 的冒泡阶段。要确定具体执行顺序,只需监听 window 和 document 上的 click 事件,并分别设置 capture 为 true 和 false,通过控制台输出日志即可验证这一固定流程。

window 和 document 在捕获阶段的执行顺序
在捕获阶段,事件从最外层容器向目标节点传递。对于 window 和 document 而言,window 对象始终比 document 节点更早触发捕获阶段的事件处理函数。这意味着当点击一个元素时,浏览器会先调用 window 上注册的 capture 回调,然后再调用 document 上注册的 capture 回调。这种顺序是固定的,不依赖于代码注册先后,而是由 DOM 层级结构决定。

const winCapture = (e) => console.log('Window Capture:', e.eventPhase); // eventPhase: 1
const docCapture = (e) => console.log('Document Capture:', e.eventPhase); // eventPhase: 1
window.addEventListener('click', winCapture, true);
document.addEventListener('click', docCapture, true);
// 预期输出:
// Window Capture: 1
// Document Capture: 1
window 和 document 在冒泡阶段的执行顺序
在冒泡阶段,事件从目标节点向外传播至根节点。此时,document 节点的冒泡处理函数会在 window 对象的冒泡处理函数之前执行。这是因为 document 是 window 的子节点(在 DOM 树中,document 位于 window 之下)。因此,当事件冒泡时,它会先经过 document,最后才到达 window。同样,这一顺序也是固定的,由 DOM 结构决定,而非代码注册顺序。
立即学习“Java免费学习笔记(深入)”;

const winBubble = (e) => console.log('Window Bubble:', e.eventPhase); // eventPhase: 3
const docBubble = (e) => console.log('Document Bubble:', e.eventPhase); // eventPhase: 3
window.addEventListener('click', winBubble, false);
document.addEventListener('click', docBubble, false);
// 假设点击 body 内的 button
// 预期输出:
// ... (中间节点冒泡)
// Document Bubble: 3
// Window Bubble: 3
基于 eventPhase 属性确认实际执行阶段
为了准确判断当前事件处于哪个阶段,可以使用 eventPhase 属性。该属性返回一个数字:1 表示捕获阶段,2 表示目标阶段,3 表示冒泡阶段。结合上述代码,我们可以清晰地看到 window 和 document 在不同阶段的具体行为。例如,在捕获阶段,window 的 eventPhase 为 1,随后 document 的 eventPhase 也为 1;在冒泡阶段,document 的 eventPhase 为 3,随后 window 的 eventPhase 也为 3。这证实了 window 和 document 在捕获和冒泡阶段中的相对位置。



















