# DOM 事件

# 1. DOM 事件冒泡与捕获

# 1.1 事件冒泡

当一个事件发生在一个元素上,它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序

# 1.2 event.target 与 event.currentTarget 的区别

父元素上的处理程序始终可以获取事件实际发生位置的详细信息。

引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过 event.target 访问。

注意与 this(=event.currentTarget)之间的区别:

  • event.target —— 是引发事件的"目标"元素,它在冒泡过程中不会发生变化。
  • this —— 是"当前"元素,其中有一个当前正在运行的处理程序。

例如,如果我们有一个处理程序 form.onclick,那么它可以"捕获"表单内的所有点击。无论点击发生在哪里,它都会冒泡到 form 并运行处理程序。

在 form.onclick 处理程序中:

  • this(=event.currentTarget)form 元素,因为处理程序在它上面运行。
  • event.target 是表单中实际被点击的元素

# 1.3 停止冒泡

冒泡事件从目标元素开始向上冒泡,但是任意处理程序都可以决定事件已经被完全处理,并停止冒泡。

用于停止冒泡的方法是 event.stopPropagation()

event.stopImmediatePropagation()event.stopPropagation() 的区别:

  • stopPropagation可以阻止事件传播,但不会影响该事件的其他监听方法执行
  • stopImmediatePropagation不仅阻止事件传播,还会阻止该事件后面的监听方法执行

# 1.4 事件捕获

事件处理的另一个阶段被称为"捕获(capturing)"

DOM 事件标准描述了事件传播的 3 个阶段:

  • 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
  • 目标阶段(Target phase)—— 事件到达目标元素。
  • 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡

添加事件element.addEventListener(event, function, useCapture)

  • 第一个参数是需要绑定的事件
  • 第二个参数是触发事件后要执行的函数
  • 第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数

总结下来有如下特点:

  • 对于非target节点则先执行捕获再执行冒泡
  • 对于target节点则是先执行先注册的事件,无论冒泡还是捕获
<div id="parent">parent
  <div id="child" onclick="console.log('child 原生')">
    child
  </div>
</div>
<script type="text/javascript">
  var parent = document.getElementById('parent')
  var child = document.getElementById('child')
  parent.addEventListener('click', function () {
    Promise.resolve().then(() => {
      console.log('parent 冒泡 promise')
    })
    console.log('parent 冒泡')
  }, false)
  child.addEventListener('click', function () {
    Promise.resolve().then(() => {
      console.log('child 冒泡 promise')
    })
    console.log('child 冒泡1')
  }, false)
  child.addEventListener('click', function () {
    console.log('child 冒泡2')
  })
  parent.addEventListener('click', function () {
    console.log('parent 捕获')
  }, true)
  child.addEventListener('click', function () {
    console.log('child 捕获')
  }, true)
  child.click();
  // parent 捕获
  // child 捕获
  // child 原生
  // child 冒泡1
  // child 冒泡2
  // parent 冒泡
  // child 冒泡 promise
  // parent 冒泡 promise
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 2. DOM 事件委托

捕获和冒泡允许我们实现一种被称为事件委托的强大事件处理模式。通俗地来讲,就是把一个元素响应事件(click...)的函数委托到另一个元素。

事件委托的优点:

  • 减少内存消耗 - 减少绑定事件
  • 动态绑定事件 - 新增元素自动绑定事件

事件委托也有一定局限性:

  • focusblur 等事件本身没有事件冒泡机制,所以无法委托
  • mousemovemouseout 等事件虽然有事件冒泡,但只能不断通过位置计算定位,对性能消耗高,因此也不适合事件委托

# 3. 参考文章

冒泡和捕获 (opens new window)

Last Updated: 9/4/2025, 2:59:15 PM