Skip to content

事件传播、默认行为与委托 ​

事件有捕获、目标和冒泡阶段。事件委托把监听放在稳定祖先上,再用 closest 找到触发项;stopPropagation() 会阻断传播,preventDefault() 只取消浏览器默认行为,两者不能混为一谈。

js
list.addEventListener('click', (event) => {
  const button = event.target.closest('button[data-id]')
  if (!button || !list.contains(button)) return
  removeTodo(button.dataset.id)
})

监听器拥有的资源必须在销毁时用相同函数和 capture 选项移除;组件反复挂载却不清理会重复执行。

练习 ​

写一个列表委托:点击删除按钮只删除对应项,点击链接仍允许默认导航,阻止删除按钮旁的嵌套链接冒泡。

核心机制与实现 ​

事件传播由捕获、目标、冒泡三个阶段组成;DOM 更新要区分节点身份、文本、属性和布局读取。

围绕“事件传播、默认行为与委托”先写出输入 → 中间状态 → 可观察结果,再实现最小闭环。不要把事件监听、异步请求、DOM 读取或 store 写入混在一个函数里;每个副作用都要有创建、完成、取消和清理路径。

js
const root = document.querySelector('[data-list]')
root.addEventListener('click', event => {
  const button = event.target.closest('button[data-id]')
  if (!button || !root.contains(button)) return
  root.dispatchEvent(new CustomEvent('item:remove', {
    bubbles: true, detail: { id: button.dataset.id }
  }))
})

逐步运行:先只验证成功路径,再改变一个输入;记录时间顺序、对象身份、错误类型和最终可见状态。若环境不支持某个浏览器 API,要把静态协议验证和真实浏览器验证分开记录。

失败边界与变体 ​

  • 输入为空、重复、过期或非法时,不应静默覆盖有效状态。
  • 组件卸载、路由离开、标签页关闭或请求取消时,资源必须停止写入。
  • 跨文档、Shadow DOM、Worker、SSR 或多标签页会改变可见边界,不能沿用单页面直觉。
  • 需要持久化时记录 schema 版本和迁移失败策略;需要全局状态时先证明局部状态不足。

可运行实验与练习 ​

用浏览器运行:点击嵌套按钮、键盘触发同一动作、移除节点后再次派发事件;记录 target、currentTarget、defaultPrevented 和节点身份。

练习要求:实现一个最小版本,补一个失败测试,再给出一个替代方案及其适用条件。答案应包括实际输入序列、观察结果、修复原因和未覆盖的浏览器差异。

查看本节答案

下一步 ​

完成练习后打开本章答案,再回到DOM 与事件课程总览。

用心记录每一步成长