事件模型

Youky ... 2021-10-11 前端
  • JS
About 3 min

# 事件模型

# 事件流的三个阶段

因为 DOM 是树结构,所以当触发子节点时,父子节点之间必然有一个顺序关系。

事件流都会经历三个阶段:

  1. 事件捕获阶段:在 DOM 树中从上到下传递(从 body 节点到具体节点)
  2. 处于目标阶段
  3. 事件冒泡阶段:在 DOM 树中从下到上传递(从具体节点到 body 节点)

# 事件模型的三种分类

# 原始事件模型(DOM0 级)

使用方法:直接在 DOM 的标签上绑定监听函数;或通过 JS 代码绑定

  • HTML 代码中直接绑定
<input type="button" onclick="fun()" />
1
  • 通过JS代码绑定
var btn = document.getElementById(".btn");
btn.onclick = fun;
1
2

特点

  • 绑定速度快
  • 只支持事件冒泡,不支持事件捕获
  • 同一个类型的事件只能绑定一个响应函数(多次绑定会进行替换)

删除方法btn.onclick=null

# 标准事件模型(DOM2 级)

该事件模型中,一共有三个过程:

  1. 捕获阶段。从document向下传递,依次检查所有元素是否绑定了监听函数,若有则执行
  2. 事件处理阶段。事件到达目标元素,触发目标元素的响应函数
  3. 事件冒泡阶段。事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行

事件绑定监听函数:

接收三个参数:事件名、响应函数、执行时机。

dom.addEventListener(eventType, handler, useCapture);
1

useCapturetrue时,会在捕获阶段执行。反之在冒泡阶段执行。

handler 接收一个 event 参数,可以获取当前元素的标签,以及当前处于的阶段(取值为 1、2、3,对应事件模型的三个阶段):

function onClickFn(event) {
  const target = event.target; // 触发事件的元素
  const currentTarget = event.currentTarget; // 当前处理元素
  const phase = event.eventPhase; // 当前阶段
}
1
2
3
4
5

事件移除监听函数:

dom.removeEventListener(eventType, handler, useCapture);
1

# IE 事件模型(基本不用)

IE 事件模型共有两个过程(即没有捕获阶段):

  • 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。
  • 事件冒泡阶段:事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行

# 事件委托

# 含义

将元素 A(可能是若干个元素)对于某个事件的响应,委托到元素 B(通常是 A 的父级元素)上执行

委托的事件会在冒泡阶段执行。

特点:

  • 提高性能
  • 减少重复工作
  • 对于没有冒泡机制的事件(如blurfocus)无法委托

# 常见场景

# 1. 多个子元素需要绑定相同的事件

一个列表有 N 个列表项,点击每一项时会输出该项的内容。

若为每个列表项绑定响应函数,则需要绑定 N 次,当 N 很大时会带来性能消耗

<ul id="list">
  <li>1</li>
  <li>2</li>
  <!-- ... -->
  <li>N</li>
</ul>
<script>
  const list = document.getElementsByTagName("li");
  for (let item of list) {
    // 需要进行N次绑定
    list.onClick = function(el) {
      console.log(el.target.innerText);
    };
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

将事件委托到父元素:

const ul = document.getElementById("list");
ul.onClick = function(el) {
  if (el.target.nodeName === "li") console.log(el.target.innerText);
};
1
2
3
4

# 2. 用户可以增删元素

例如存在增/删的按钮,每次点击会增/删列表元素,那么在这种情况下就需要频繁的进行事件的绑定和解绑。

将事件委托到父元素则没有这种问题

Last update: October 16, 2022 21:28
Contributors: youky7 , Youky