菜单

虚拟 DOM 实现

相关源文件

目的与范围

本文档解释了 Vue 的虚拟 DOM 实现,它是 Vue 渲染系统的基础。虚拟 DOM(VDOM)使 Vue 能够通过差异算法执行协调(reconciliation),从而高效地更新真实 DOM。这种方法最大限度地减少了直接的 DOM 操作,这些操作在性能方面是昂贵的。

有关更广泛的渲染管道和组件系统的信息,请参阅组件系统响应式系统

什么是虚拟 DOM?

虚拟 DOM 是对实际 DOM 的抽象,表现为轻量级的 JavaScript 对象,称为 VNode。当组件的状态改变时,Vue 会生成一个新的虚拟 DOM 树并与前一个进行比较,以确定更新真实 DOM 所需的最少 DOM 操作。

来源:types/vnode.d.ts, types/vue.d.ts

VNode 结构

Vue 虚拟 DOM 的核心是 VNode 接口,它代表了虚拟 DOM 树中的节点。VNode 是对实际 DOM 节点的轻量级描述。

来源:types/vnode.d.ts

VNode 可以表示几种不同类型的 DOM 元素

  1. 普通 HTML 元素 - 通过 tag 属性中的标签名表示
  2. 组件元素 - 包含带有构造函数引用的 componentOptions
  3. 文本节点 - 在 text 属性中包含文本,且没有 tag
  4. 注释节点 - 通过 isComment: true 标记
  5. 片段 - 一个具有多个根节点(表示为子节点)的 VNode

key 属性对于列表渲染尤其重要,因为它有助于 Vue 在更新列表时识别哪些节点已更改。

CreateElement 函数

Vue 提供了一个用于创建 VNode 的 createElement 函数(通常别名为 h)。此函数暴露给渲染函数,是程序化创建 VNode 的主要方式。

来源:types/vue.d.ts

CreateElement 函数签名

该函数可以通过两种方式调用

  1. 带标签和子节点
  2. 带标签、数据(属性、props 等)和子节点

子节点可以是字符串、VNode 数组或各种其他类型,Vue 会通过规范化(normalization)来处理这些类型。

打补丁算法

打补丁算法是 Vue VDOM 实现的核心。它通过仅应用必要的更改来高效地更新真实 DOM。

来源:types/vue.d.ts, types/vnode.d.ts

打补丁过程遵循以下关键步骤

  1. 节点比较:确定旧节点和新节点是否为相同类型
  2. 元素替换:如果节点类型不同,则完全替换旧节点
  3. 节点打补丁:如果节点类型相同,则更新现有的 DOM 元素
    • 更新属性、类、样式、事件监听器等。
    • 使用高效的差异算法更新子节点
    • 如果是组件节点,则处理组件更新

子节点差异算法

当 Vue 更新子节点列表时,它使用一种复杂的算法来最小化 DOM 操作。这对于处理大型列表时的性能尤其重要。

来源:types/vnode.d.ts

子节点差异算法使用多种优化

  1. 首尾指针:首先检查常见模式(开头或结尾相同的项)
  2. 基于 Key 的匹配:使用 key 快速识别移动的节点
  3. 最小化移动:尝试最小化 DOM 操作的数量

组件 VNode 和生命周期

组件 VNode 在虚拟 DOM 系统中有特殊的处理方式

来源:types/vnode.d.ts, types/options.d.ts

当组件 VNode 被创建和打补丁时

  1. 如果组件实例不存在,Vue 会创建一个组件实例
  2. 组件的渲染函数生成其虚拟 DOM 树
  3. 打补丁过程在组件的子节点上递归运行
  4. 生命周期钩子在适当的时间被调用

Vue VDOM 实现的关键方面

  1. 效率:Vue 的差异算法针对常见用例进行了优化
  2. 组件友好:对组件 VNode 进行特殊处理
  3. 指令:支持可以操作 DOM 节点的指令
  4. 函数式组件:支持无状态组件并优化渲染
  5. 钩子:VNode 生命周期中的各种钩子用于扩展

函数式组件

函数式组件是 Vue VDOM 实现中的一个特例。它们是无状态的,没有实例,并且渲染效率更高。

来源:types/options.d.ts, types/test/options-test.ts

函数式组件通过 functional: true 属性和渲染函数来定义。它们接收渲染上下文而不是拥有 this,这使它们渲染速度更快,因为它们跳过了实例创建过程。

与其他系统的关系

Vue 的虚拟 DOM 是 Vue.js 架构的核心部分,连接了其他几个系统

来源:项目概览图

总结

Vue 的虚拟 DOM 实现提供了一个组件状态与真实 DOM 之间的高效抽象层。通过使用 DOM 结构的轻量级 JavaScript 表示和优化的差异算法,Vue 最大限度地减少了实际的 DOM 操作,从而提高了性能。VDOM 系统处理不同类型的节点(元素、组件、文本),支持指令,并与 Vue 的响应式系统无缝集成,以提供响应式用户界面。