前端升级打怪路:DOM事件和事件委托

609 阅读3分钟

DOM事件 : 捕获 和 冒泡

<html lang="en">
<body>
<table>
<tr>
    <td>P</td>
</tr>
</table>
</body>
</html>
  • 请问点击鼠标点击P的时候发生了什么?
    • 答: 点击的时候事件会经历三个阶段:
      1. 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
      2. 目标阶段(Target phase)—— 事件到达目标元素。
      3. 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
        未命名
  1. 捕获阶段(Capturing phase)
    • 点击后,首先会从window开始运行,监听
    • 然后在Dounment上运行,监听
    • 然后是在上<html>运行,监听
    • 然后是在上<body>运行,监听
    • 然后是在上<table>运行,监听
    • 然后是在上<tbody>运行,监听
    • 直到最后在<td>上捕获P(此就到达目标属于(目标阶段))
    • 一层一层的向下捕获
  2. 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡
  • 点击后,首先会从window开始运行,监听
    • 首先从目标阶段<td>上开始运行,监听
    • 然后是在<tr>上运行,监听
    • 然后是在<tbody>上运行,监听
    • 然后是在<table>上运行,监听
    • 然后是在<body>上运行,监听
    • 然后是在<body>上运行,监听
    • 然后是在上<html>运行,监听
    • 然后在Dounment上运行,监听
    • 最后到底window
    • 一层一层向上浮动
  1. 点击 <td>,事件首先通过祖先链向下到达元素(捕获阶段),然后到达目标(目标阶段),最后上升(冒泡阶段),在途中调用处理程序。

  2. 注意的是: 所有事件,都是先捕获阶段,然后冒泡阶段,按照这样的顺序进行的

捕获和冒泡不同阶段设置处理程序

  • 处理程序的 capture 选项设置
elem.addEventListener(..., {capture: true}) 
//如果capture为 true,则在捕获阶段设置处理程序。
elem.addEventListener(..., {capture: true})
//如果capture为 false,则在冒泡阶段设置处理程序。

例子:
elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
//捕获阶段设置处理程序
elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
// 冒泡阶段设置处理程序

DOM事件总结

当一个事件发生时 —— 发生该事件的嵌套最深的元素被标记为“目标元素”(event.target)。

  • 然后,事件从文档根节点向下移动到 event.target,并在途中调用分配了 addEventListener(..., true) 的处理程序(true 是 {capture: true} 的一个简写形式)。 然后,在目标元素自身上调用处理程序。
  • 然后,事件从 event.target 向上移动到根,调用使用 on 和没有第三个参数的,或者第三个参数为 false/{capture:false} 的 addEventListener 分配的处理程序。
  • 每个处理程序都可以访问 event 对象的属性:
  1. event.target —— 引发事件的层级最深的元素--用户操作的元素
  2. event.currentTarget(=this)—— 处理事件的当前元素(具有处理程序的元素)--程序员监听的元素
  3. event.eventPhase —— 当前阶段。

事件委托

  • 什么是事件委托?
    • 答:监听祖先元素 : 捕获和冒泡允许我们实现一种被称为事件委托的强大的事件处理模式.
      • 如果我们有许多类似的方式要处理元素,那么就不必为每个元素分配一个处理程序 —— 而是将单个处理程序放在它们的共同祖先上 => 即监听祖先元素
      • 优点: 1. 省内存 2. 可以监听动态元素