一、介绍
捕获阶段(Capturing Phase):从window对象向下传播到目标元素
目标阶段(Target Phase):在事件目标上触发
冒泡阶段(Bubbling Phase):从目标元素向上传播回window对象
// 捕获阶段触发(第三个参数为true)
element.addEventListener('click', handler, true);
// 冒泡阶段触发(默认false)
element.addEventListener('click', handler, false);
// 或
element.addEventListener('click', handler);
// 适时移除
element.removeEventListener('click', handler);
二、常见事件的冒泡情况
1.不会冒泡事件
类型 | 常见事件 | 说明 |
焦点事件 | focus, blur | 使用 focusin/focusout 代替可冒泡版本 |
加载类事件 | load, unload, beforeunload, DOMContentLoaded | 这些事件一般只发生在特定元素(如 window, document) |
表单类事件 | resize, scroll, abort, error | 作用于元素自身,不具备冒泡意义 |
鼠标事件 | mouseenter、mouseleave | |
媒体事件 | play, pause, playing, ended 等 | 通常不冒泡 |
剪贴板事件 | copy, cut, paste (某些浏览器冒泡不一致) | |
2.会冒泡事件
类型 | 常见事件 |
鼠标事件 | click, dblclick, mousedown, mouseup, contextmenu |
表单事件 | input, change, focusin, focusout (注意区别于 focus 和 blur) |
键盘事件 | keydown, keyup, keypress |
触摸事件 | touchstart, touchend, touchmove |
拖拽事件 | dragstart, dragend, dragenter, dragleave, dragover, drop |
其他 | submit, reset, pointerdown, pointerup, pointermove, wheel |
三、相关操作
1.判断事件是否冒泡
console.log(Event.prototype.bubbles); // false,默认值
2.阻止事件冒泡
// 方法1:event.stopPropagation()
document.getElementById('inner').addEventListener('click', (e) => {
console.log('Inner clicked');
e.stopPropagation(); // 阻止向上冒泡
});
// 方法2:return false (jQuery特有方式)
$('#inner').on('click', () => {
console.log('Inner clicked');
return false; // 同时阻止冒泡和默认行为
});
// 方法3:event.stopImmediatePropagation()
document.getElementById('inner').addEventListener('click', (e) => {
console.log('First handler');
e.stopImmediatePropagation(); // 阻止其他监听器和冒泡
});
3.访问事件的目标和当前目标
<div id="parent">
<button id="child">Click Me</button>
</div>
<script>
const parent = document.getElementById("parent");
parent.addEventListener("click", function (event) {
console.log('currentTarget:', e.currentTarget); // 当前绑定事件的元素(监听器所在的),即parent
console.log('target:', e.target); // 实际触发事件的元素(真正点击的),即child
});
</script>
4.通过创建事件手动设置是否冒泡
const customEvent = new Event('my-event', { bubbles: true });
四、案例题目
<div id="outer">
<div id="inner">
<button id="btn">Click Me</button>
</div>
</div>
<script>
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
const btn = document.getElementById("btn");
outer.addEventListener("click", () => {
console.log("outer capture");
}, true);
outer.addEventListener("click", () => {
console.log("outer bubble");
});
inner.addEventListener("click", (e) => {
console.log("inner capture");
}, true);
inner.addEventListener("click", (e) => {
console.log("inner bubble");
e.stopPropagation();
});
btn.addEventListener("click", () => {
console.log("btn click");
});
</script>
结果:
outer capture // 捕获阶段
inner capture // 捕获阶段
btn click // 目标阶段
inner bubble // 冒泡阶段,因为阻止冒泡了,所以outer bubble不打印