浏览器的事件流一共分两大阶段:
捕获阶段(往下)
事件从最外层(window
)一路往目标元素「往下走」,依次经过祖先节点──这就是“往下”的意思。
目标阶段
事件到达目标元素本身。
冒泡阶段(往上)
事件再从目标往外冒泡回去,依次经过父节点──这就是“往上”的意思。
e.stopPropagation()
默认情况下,如果你不给它 capture: true
,浏览器只给你触发“冒泡阶段”下的监听器。
在任何一个阶段(捕获或冒泡)里调用 stopPropagation()
,都可以阻止该事件流在当前阶段及后续阶段继续向上/向下。
// 捕获阶段拦截
el.addEventListener('click', e => {
console.log('捕获到 click,往下不会继续了');
e.stopPropagation();
}, true); // 第三个参数 true:在捕获阶段触发
// 冒泡阶段拦截
el.addEventListener('click', e => {
console.log('冒泡到这里就停了,不会往上继续冒泡');
e.stopPropagation();
});
注意:stopPropagation()
并不是只能阻止“往上”(冒泡),它也能阻止“往下”(捕获)——前提是你要在捕获阶段就调用它。
注册一个捕获阶段的监听器
parent.addEventListener('click', handler, { capture: true });
在 handler 里调用 stopPropagation()
function handler(e) {
// 这里在捕获阶段就把事件流给拦截住,
// 下面的子节点就收不到这个事件了
e.stopPropagation();
}
这样就能在事件“往下”到子元素之前拦截它,子元素上的任何 click listener(不论是捕获还是冒泡阶段)都不会被触发。
e.stopImmediatePropagation()
除了阻止事件继续传播,还会阻止当前元素上后续同类型的其他监听器被调用。
capture: true
指明这个监听器在捕获阶段(往下)生效;默认是 false
,也就是冒泡阶段(往上)生效。
总结: