事件:冒泡、委托与默认行为

每做一次操作,控制台会输出事件链上发生了什么。

[迷你控制台]

一、事件对象:target 与 currentTarget,顺带看冒泡全链

// 同一个点击,会从最外层往里「捕获」,再往外「冒泡」:
//   lvl1 捕获 → lvl2 捕获 → 目标 → lvl2 冒泡 → lvl1 冒泡
// 监听器挂在哪个元素,currentTarget 就是谁;e.target 始终是实际被点的那个
lvl1(祖父)
lvl2(父)

二、事件委托:容器绑一次,子孙随便换

ul.addEventListener('click', (e) => {
  const li = e.target.closest('.item')   // 不管点中 li、文字还是 ×,都先回到条目
  if (!li) return
  if (e.target.closest('.del')) { li.remove(); return }   // 点的是删除
  li.classList.toggle('done')                              // 否则切换完成
})

三、preventDefault:拦下浏览器的默认动作

link.addEventListener('click', (e) => {
  e.preventDefault()          // 取消默认跳转/滚动,然后自己决定做什么
  // …例如:先校验、先弹确认框
})
不拦截:滚到红框 · 拦截后:只打日志,不滚动

四、键盘事件:e.key 认出按了什么

input.addEventListener('keydown', (e) => {
  console.log(e.key)              // 'a'、'Enter'、'ArrowUp'、'Shift'…
  if (e.key === 'Enter') { … }    // 回车提交是最高频用法
})

五、removeEventListener 与 once

zone.addEventListener('click', onZoneClick)
zone.removeEventListener('click', onZoneClick)   // 必须传同一个函数引用才移除得掉

btn.addEventListener('click', handler, { once: true })   // 只响应一次,自动移除
目标框:上面「不拦截」的链接会滚到这里;「拦截后」的链接不会。表单的默认提交同理(先拦下、校验通过再放行),第十六章完整展开。