当前位置: 首页 > news >正文

JavaScript 事件冒泡与事件捕获

1. 什么是事件流?

当浏览器中的某个元素触发了一个事件(比如 click),这个事件并不是只在触发元素上执行一次,而是会按照特定的顺序在不同的 DOM 节点之间传播,这个传播过程就是事件流

DOM 事件流分为三个阶段:

  1. 事件捕获阶段(Capture Phase)
  2. 目标阶段(Target Phase)
  3. 事件冒泡阶段(Bubbling Phase)

注意:在旧版本 IE(IE8 及以下)中,只支持事件冒泡,不支持事件捕获。

2. 事件捕获(Event Capture)

  • 方向:从最外层的祖先元素(通常是 window)向内传播,直到目标元素。
  • 触发顺序:先触发父级元素的事件处理程序,再到子级。
  • 语法:在 addEventListener 的第三个参数设为 true 时,表示在捕获阶段执行。
<div id="grandparent" style="padding:20px; background:red;">祖父<div id="parent" style="padding:20px; background:green;">父亲<div id="child" style="padding:20px; background:blue;">儿子</div></div>
</div><script>const grandparent = document.getElementById('grandparent');const parent = document.getElementById('parent');const child = document.getElementById('child');grandparent.addEventListener('click', () => {console.log('捕获阶段:祖父');}, true);parent.addEventListener('click', () => {console.log('捕获阶段:父亲');}, true);child.addEventListener('click', () => {console.log('捕获阶段:儿子');}, true);
</script>

点击 “儿子” 元素的输出:

原因:事件从最外层(祖父)向目标(儿子)传播

3. 事件冒泡(Event Bubbling)

  • 方向:从目标元素向外传播,逐级向上,直到 window
  • 触发顺序:先触发子级元素的事件处理程序,再到父级。
  • 语法addEventListener 默认(第三个参数为 false)就是在冒泡阶段执行。
<div id="grandparent" style="padding:20px; background:red;">祖父<div id="parent" style="padding:20px; background:green;">父亲<div id="child" style="padding:20px; background:blue;">儿子</div></div>
</div><script>const grandparent = document.getElementById('grandparent');const parent = document.getElementById('parent');const child = document.getElementById('child');grandparent.addEventListener('click', () => {console.log('冒泡阶段:祖父');}, false);parent.addEventListener('click', () => {console.log('冒泡阶段:父亲');}, false);child.addEventListener('click', () => {console.log('冒泡阶段:儿子');}, false);
</script>

点击 “儿子” 元素的输出:

原因:事件从目标(儿子)向父级(父亲、祖父)传播。

4. 完整事件流顺序

结合捕获和冒泡,完整的触发顺序是:

  1. 捕获阶段:从 window → document → html → ... → 目标元素
  2. 目标阶段:事件在目标元素上触发
  3. 冒泡阶段:从目标元素 → ... → html → document → window
<div id="outer" style="padding:20px; background:yellow;">外层<div id="inner" style="padding:20px; background:orange;">内层</div>
</div><script>const outer = document.getElementById('outer');const inner = document.getElementById('inner');outer.addEventListener('click', () => console.log('捕获:outer'), true);inner.addEventListener('click', () => console.log('捕获:inner'), true);outer.addEventListener('click', () => console.log('冒泡:outer'), false);inner.addEventListener('click', () => console.log('冒泡:inner'), false);
</script>

点击 “内层” 输出:

5. 如何阻止事件冒泡?

在实际开发中,有时我们不想让事件继续向上传播(比如点击按钮时不想触发父级的点击事件),可以使用:

方法 1:event.stopPropagation()

<div id="parent" style="padding:20px; background:green;">父亲<button id="btn">点我</button>
</div><script>const parent = document.getElementById('parent');const btn = document.getElementById('btn');parent.addEventListener('click', () => {console.log('父元素被点击');});btn.addEventListener('click', (e) => {console.log('按钮被点击');e.stopPropagation(); // 阻止事件冒泡});
</script>

点击按钮输出:

不会触发父元素的点击事件。

方法 2:event.stopImmediatePropagation()

  • 不仅阻止事件冒泡,还会阻止当前元素后面注册的相同类型事件的执行。
<button id="btn">按钮</button><script>const btn = document.getElementById('btn');btn.addEventListener('click', (e) => {console.log('第一个点击事件');e.stopImmediatePropagation();});btn.addEventListener('click', () => {console.log('第二个点击事件'); // 不会执行});
</script>

点击按钮输出:

6. 实际开发中的应用场景

  1. 事件委托(Event Delegation)利用事件冒泡,将子元素的事件监听委托给父元素,减少监听器数量,提高性能。
  2. 防止父级元素事件被误触发例如点击关闭按钮时,避免触发整个弹窗的点击事件。
  3. 自定义组件事件控制控制组件内部事件是否向外传播。

. 总结

  • 事件捕获:从外向内传播,addEventListener(..., true)
  • 事件冒泡:从内向外传播,addEventListener(..., false)(默认)
  • 阻止冒泡event.stopPropagation()
  • 阻止冒泡 + 阻止后续同类型事件event.stopImmediatePropagation()

7.事件捕获与冒泡的完整流程图

假设我们有三层嵌套元素:

完整事件流顺序图

图解说明

  1. 捕获阶段(Capture Phase)

    • 事件从最顶层的 window 对象开始向下传播
    • 依次经过 document → html → body → ... → 目标元素的父级
    • 在这个阶段注册的事件监听器(addEventListener(..., true))会被触发
  2. 目标阶段(Target Phase)

    • 事件到达实际触发的元素(目标元素)
    • 在这个阶段,无论捕获还是冒泡的监听器都会按照注册顺序执行
  3. 冒泡阶段(Bubbling Phase)

    • 事件从目标元素向上传播
    • 依次经过父级 → ... → body → html → document → window
    • 在这个阶段注册的事件监听器(addEventListener(..., false) 或默认)会被触发

http://www.dtcms.com/a/411840.html

相关文章:

  • 外贸网站源码怎么建wordpress使用百度分享插件下载
  • C语言基础【26】:结构体2
  • 项目计划书模板10篇win7优化大师
  • SQL Server提示:安装程序无法与下载服务器联系。请提供 Microsoft机器学习服务器安装文件的位置。。。。
  • 无人机表演行业二手设备市场与性价比分析
  • 快速建站公司怎么样wordpress读取父分类列表
  • 黄埔网站建设厦门网站排名
  • 好的ftp网站宁夏住房和城乡建设官方网站
  • Redis 7.0 新特性深度解读:迈向生产级的新纪元
  • wordpress网站实例网站怎么建设后台
  • JVM内存分配
  • 兴化网站建设网站开发用什么语言比较好
  • 四川网站建设找珊瑚云公司装修通知告示怎么写
  • 从 inode 角度深入分析软硬链接的内核实现与设计
  • 游戏开发中的状态管理与定时器
  • 上海网站开发外包分类信息网站
  • Apifox+DeepSeek接口测试实战
  • 7、幽络源微服务项目实战:SpringSecurity用户权限查询与校验的配置和测试
  • 海丰县建设局官方网站南县网站制作
  • 重庆企业建站模板佛山全网营销推广
  • 基于C#的停车场管理系统实现
  • html怎么做网站wordpress还能用
  • 有域名和空间怎么做网站简单网站设计网站
  • 操作系统之初识Linux
  • Transformers Dataset 完全指南:从基础到高级应用
  • 建设工程教育网站重庆网站推广多少钱
  • 广饶网站建设chenqinghua wordpress
  • (ST 表、博弈)洛谷 P8818 CSP-S 2022 策略游戏 题解
  • 怎么在百度搜索到我的网站一个互联网公司可以做几个网站
  • LangChain核心组件最新文档及示例代码(2025年更新)