Vue3渲染机制
- Vue如何将模板 =》 转换为实际的DOM节点?
- Vue如何高效更新这些DOM节点??
虚拟DOM => Vue渲染系统的根基
虚拟DOM(VDOM) =》 编程概念:将内存中的虚拟DOM和真实节点同步
// 运行时渲染器 =》 遍历虚拟DOM树 =》 构建真实DOM树 ===》 mount
const vnode = { // 代表元素的纯JS对象
type: 'div',
props: {
id: 'hello'
},
children: [
// more vnodes
]
}
“diffing Or reconciliation” PATH过程: 内存中存在两份虚拟DOM的副本,渲染器可以遍历并比较这两颗树,找出差异,并将这些更改应用到真实DOM
虚拟DOM(VDOM)的好处:开发人员只需要关注数据展示和数据的处理逻辑,将直接的DOM操作交给渲染器完成。
渲染管道
Vue挂载流程:
- 编译:Vue模板被编译为渲染函数:返回虚拟DOM树的函数。
- Mount: 运行时渲染器调用 =》 渲染函数,遍历返回的虚拟DOM树,基于该过程构建实际的DOM节点(该阶段会追踪所有使用过的响应依赖项
- Patch: 当挂载期间使用的依赖项发生变化是,效果将重新运行,将创建一个新的、更新的虚拟DOM树。运行时渲染器将遍历新的VDOM树和旧的VDOM树进行比较,将必要的更新应用到实际的DOM上

模板和渲染函数
Vue模板 ====》编译成 ===》虚拟DOM渲染函数
Vue为什么推荐使用模板而不是像React中使用JSX
- 模板更加接近HTML,便于开发人员理解和维护
- 模板语法更具确定性,容易进行静态分析,Vue模板编译器可应用许多编译时优化来提供虚拟DOM性能
React VDOM VS Vue VDOM
React中的虚拟DOM是纯运行时的,调和算法必须对传入的虚拟DOM完全遍历
Vue中的虚拟DOM是同时控制编译器和运行时
编译器可以静态分析模板并在生成的代码中留下静态标记,便于提高运行时的渲染效率
🚨Vue模板编译器为提高虚拟DOM的运行时性能做出的几个主要优化:
☘️静态提升
<div>
<div>foo</div> <!-- hoisted -->
<div>bar</div> <!-- hoisted -->
<div>{{ dynamic }}</div>
</div>
对于不包含任何动态绑定的静态节点,每次重新渲染时无需重新创建对应VNode并对其进行Diff处理
对于大量连续的静态VNode会被压缩成单个静态VNode,静态VNode会通过innerHTML直接挂载
☘️补丁标志(Path Flags)
<!-- class binding only -->
<div :class="{ active }"></div>
<!-- id and value bindings only -->
<input :id="id" :value="value">
<!-- text children only -->
<div>{{ dynamic }}</div>
createElementVNode("div", {
class: _normalizeClass({ active: _ctx.active })
}, null, 2 /* CLASS */)
// 运行时渲染器可以使用按位运算检查标志,以确定是否需要执行某些工作
// 最后一个参数2是补丁标志。一个元素可以有多个补丁标志,这些标志将合并为一个数字。然后,运行时渲染器可以使 // 用按位运算检查标志,以确定是否需要执行某些工作:
☘️树扁平化

当此组件需要重新渲染时,它只需要遍历扁平化的树,而不需要遍历整个树。这称为树扁平化,它大大减少了虚拟 DOM 协调期间需要遍历的节点数。模板的任何静态部分都会被有效跳过。
渲染函数和JSX
基本用法
创建VNode
import { h } from 'vue'
const vnode = h(
'div', // type
{id: 'foo', class: 'bar'}, // props
[
// children
]
)
h()是hyperscript的缩写即生成HTML的JavaScript
h()函数实际上就是createVNode(),用来创建虚拟DOM
学而不思则罔,思而不学则殆!

浙公网安备 33010602011771号