前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库不冒泡事件 事件委托 无法捕获
浏览器事件系统

哪些事件不能直接靠冒泡委托?

默认冒泡委托要求事件会经过父级的冒泡阶段。focus、blur、mouseenter、mouseleave 等不按这一路径冒泡,因此父级默认监听不能直接照搬 click 的写法。

前端进阶之旅 · 一题精讲更新于 2026.09.29
浏览器#事件系统
先看核心答案读代码示例
理解线索

委托依赖事件传播方式

  1. 冒泡委托父级在子项之后接收事件
  2. focusin可冒泡的焦点进入事件
  3. 捕获监听父级在事件到目标前观察

mouseover 会在穿越子节点时重复触发,替代 mouseenter 时需过滤相关目标。

核心回答

先记住这个答案

事件委托常说“给父级绑一次监听”,默认前提是事件会冒泡。focus、blur 不冒泡,父级可改听 focusin、focusout,或在捕获阶段听原事件;mouseenter、mouseleave 也不冒泡,可根据需求用会冒泡的 mouseover、mouseout,但进入内部子元素时它们还会额外触发,不能不加过滤地替代。

  • focus、blur 不冒泡
  • mouseenter、mouseleave 不冒泡
  • 可用 focusin、focusout 替代
  • 捕获阶段也能观察部分事件

表单字段聚焦时高亮所在行

一张动态表格里有许多输入框,希望当前行高亮。直接在表格上默认监听 focus 收不到子输入框的冒泡事件;改听 focusin 就能从父级处理。

用 focusin 做委托JavaScript
const table = document.querySelector('#editor')
table.addEventListener('focusin', event => {
  const row = event.target.closest('tr')
  if (row && table.contains(row)) row.classList.add('active')
})
table.addEventListener('focusout', event => {
  const row = event.target.closest('tr')
  // 焦点仍在同一行的另一个控件上时,保留高亮
  if (row && !row.contains(event.relatedTarget)) {
    row.classList.remove('active')
  }
})

新加入的行也能通过父级监听得到聚焦反馈。focusout 的 relatedTarget 是即将获得焦点的元素;它仍在原行内时保留高亮,跨到别行或离开表格才移除。若目标为空,例如焦点移出页面,contains(null) 为假,也会移除高亮。 另一种方法是在祖先注册 { capture: true } 的 focus 监听。它利用捕获路径,不意味着 focus 突然变成了冒泡事件。

鼠标进入事件不能机械替换

mouseenter 表达进入一个元素整体,通常不会像 mouseover 那样沿普通冒泡路径到父级。mouseover 可以委托,但指针从父项移入其内部按钮时也可能再触发。

需要“首次进入某个列表项”时,结合 relatedTarget 判断指针是否原本已经在同一项内。事件类型选错会造成反复打开提示层或重复埋点。

具体做法是先用 event.target.closest() 找到当前列表项,再检查 relatedTarget 是否仍被该项包含。若从项里的图标移到文字,两个目标都在同一项内,不应算重新进入;若从另一项移来,才执行“进入”逻辑。离开时用 mouseout 做相反检查,避免鼠标在内部子元素之间移动时反复关闭浮层。

触摸设备没有与鼠标悬停完全对应的操作,所以重要功能不能只靠 mouseover 或 mouseenter 暴露。悬停提示可以是补充反馈,真正的操作仍应有点击或聚焦后的可用入口。事件委托解决监听位置,不会自动解决输入方式差异。

回答前,多想一步

容易答错的地方

以为不冒泡就完全不能在祖先监听
捕获阶段可能观察到事件,或者有语义相近的可冒泡替代事件。
把 mouseover 当成完全等价的 mouseenter
进入子元素时它可能再次触发,需要检查 relatedTarget 与业务边界。
试着用自己的话回答

面试官还会怎么问?

focus 的委托替代事件是什么?

常用 focusin;离开对应 focusout。

为什么 click 比 focus 更容易委托?

通常 click 会冒泡到父级,默认监听即可接收。

事件设置了 bubbles: false 时能捕获吗?

若事件传播路径经过祖先,捕获监听仍可能观察到;只是默认冒泡监听收不到。

从一道题,走向一组知识

把知识连起来

事件系统

哪些场景要把监听器放在捕获阶段?

祖先捕获 focus 是处理不冒泡事件的一种办法。

事件系统

动态新增的列表项,为什么一个父级点击监听就够?

动态列表的 click 委托之所以自然,是因为点击通常会冒泡。

参考资料

  • Event: bubbles property

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 表单字段聚焦时高亮所在行
  3. 鼠标进入事件不能机械替换
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑