本文档涵盖了 Vue.js 的虚拟 DOM 实现,这是 Vue 渲染系统的核心部分。虚拟 DOM 在组件状态和实际 DOM 之间提供了一个抽象层,实现了高效的更新和跨平台渲染能力。有关使用虚拟 DOM 的渲染器实现信息,请参阅 渲染系统。
虚拟 DOM 是实际 DOM 的轻量级 JavaScript 表示。在 Vue 中,它以 VNode(虚拟节点)对象的树的形式存在,这些对象由组件的渲染函数生成。当应用程序状态发生变化时,Vue 不会直接操作 DOM,而是先更新这个虚拟表示,将其与前一个版本进行比较,然后仅将必要的最小更改应用到真实 DOM。
来源
VNode(虚拟节点)是 Vue 虚拟 DOM 的基本构建块,它代表 UI 中的一个元素、组件或片段。每个 VNode 都包含创建和更新真实 DOM 节点所需的所有信息。
来源
VNode 接口包含几个关键属性
type: 标识节点类型(HTML 元素为字符串,组件为组件对象)props: 包含节点的属性和特性children: 包含子 VNode 或文本el: 指向实际 DOM 节点(挂载前为 null)shapeFlag: 位标志,用于快速识别节点特征patchFlag: 优化标志,指示节点可能需要的更新类型dynamicChildren: 用于跟踪块优化的节点的可选数组Vue 使用几种特殊的 VNode 类型和标志来优化渲染
来源
特殊 VNode 类型包括
Fragment: 聚合多个节点而不添加额外的 DOM 元素Text: 表示文本内容Comment: 表示 HTML 注释Static: 表示永不变动的静态内容Teleport: 用于将子节点渲染到 DOM 中其他位置的特殊组件Suspense: 用于处理异步依赖的组件createVNode 函数是创建虚拟节点的关键 API。它通常由组件的渲染函数调用。
来源
创建过程包括
Vue 使用块树机制来优化更新。块是跟踪其动态子项的 VNode,这使得 Vue 在更新期间可以跳过树的静态部分。
来源
块树提供了多种优化
dynamicChildren 跟踪)进行 diffv-if 和 v-for 这样的结构指令会创建自己的块当组件状态更改时,Vue 会创建一个新的 VNode 树并将其与之前的树进行比较。这个过程称为“打补丁”(patching),负责高效地更新 DOM。
来源
打补丁算法
Vue 使用不同的策略来打补丁 VNode 树的不同部分
来源
打补丁过程通过多种方式进行了优化
shapeFlag 快速识别节点结构类型patchFlag 只更新需要更新的特定属性dynamicChildren 直接打补丁动态节点,跳过树遍历当组件状态更改时,虚拟 DOM 由 Vue 的响应性系统触发。这两个系统之间的连接通过 effects 和 scheduler 建立。
来源
响应性被触发时
Vue 中的组件被表示为具有特殊处理的 VNode。组件实例维护一个指向其对应 VNode 和根 VNode 树的引用。
来源
组件与虚拟 DOM 的关系
vnode 属性,指向其 VNode 表示subTree 属性指向组件渲染函数生成的 VNode 树component 属性,指向其实例Props 通过 VNodes 从父组件传递到子组件。Vue 的 Props 处理包括验证、默认值和类型转换。
来源
Props 处理过程
Vue 的虚拟 DOM 包含多种优化技术以提高性能
来源
关键优化技术
虚拟 DOM 与 Vue 的组件生命周期系统紧密集成,钩子在挂载和更新过程的特定阶段触发。
来源
Vue 的生命周期钩子在虚拟 DOM 操作的特定阶段触发
beforeMount:在初始渲染应用于 DOM 之前mounted:在 DOM 被初始更新后beforeUpdate:在因响应性更改而重新渲染之前updated:在 DOM 被更新后beforeUnmount:在组件被从 DOM 中移除之前unmounted:在组件被完全移除后虚拟 DOM 抽象允许 Vue 针对不同的渲染平台,而不仅仅是浏览器 DOM。
来源
渲染器 API 允许 Vue
Vue 的虚拟 DOM 系统作为组件逻辑和实际 DOM 操作之间的强大抽象层。通过使用轻量级的 VNode 表示和高效的补丁算法,Vue 在提供声明式编程模型的同时,最大限度地减少了昂贵的 DOM 操作。该系统的优化,如块树机制和补丁标志,使 Vue 能够在保持灵活的组件模型的同时实现高性能。
虚拟 DOM 还通过抽象实际的渲染实现,使相同的代码库能够跨浏览器、服务器和自定义渲染目标工作,从而实现了 Vue 的跨平台功能。