Vue3 Virtual DOM & 渲染机制
# 🧠 1. Vue3 Virtual DOM 的设计目标
Vue3 的 Virtual DOM 不是 React 那种纯 VDOM,而是:
“带编译优化的 Virtual DOM” template → Compiler → 最小化的 VDOM 对象 + 静态标记(patchFlags) → Runtime diff 更快
Vue3 的设计核心是: 减少 VDOM 计算量,减少对比次数,尽可能生成编译期可确定的内容。
所以它比 React 更快,特别是大量静态模板的情况下。
# 🧩 2. Vue3 渲染流程(runtime)
Vue3 主要由两部分组成:
- reactivity 响应式系统 —— 负责依赖追踪
- runtime-core 渲染系统 —— 负责 VDOM → DOM
渲染大致流程如下:
template → compiler-dom (生成 render 函数)
↓
render() 生成 vnode 树
↓
patch(vnode, container)
↓
操作真实 DOM
2
3
4
5
6
7
Vue3 的 render 函数内部使用:
- h() / createVNode():创建虚拟节点
- patch():对比新旧 vnode
- effect():组件渲染响应式收集器
# 🔧 3. VNode(虚拟节点)是什么?
JS 对象,用来描述 DOM:
const vnode = {
type: 'div',
props: { id: 'app' },
children: 'Hello'
}
2
3
4
5
Vue3 内部使用 createVNode() 来创建:
export function createVNode(type, props, children) {
return {
type,
props,
children,
shapeFlag: xxx, // 节点类型(元素、组件、文本…)
patchFlag: xxx, // 静态标记(更快 diff)
}
}
2
3
4
5
6
7
8
9
重点字段:
- shapeFlag:快速判断节点类型(不需要频繁 typeof)
- patchFlag:编译期注入的优化标记(避免全量 diff)
# 🎯 4. 响应式系统如何触发重新渲染?
Vue3 的响应式核心是:
effect(fn):收集依赖(组件渲染函数)track():记录依赖trigger():触发更新(调度渲染)
在组件挂载时,会执行:
effect(() => {
component.update()
})
2
3
当响应数据变更时:
trigger(obj.key)
→ scheduler
→ 重新执行组件的 update() → patch()
2
3
🔵 这里的关键:渲染函数本身是一个 effect,因此数据变化 = 重新生成 vnode 树 → diff
# 🧮 5. Diff 过程(核心 patch)
Vue3 patch 的核心逻辑:
patch(n1, n2, container) {
if (!n1) {
mount(n2)
} else if (n1.type !== n2.type) {
replace(n1, n2)
} else {
patchElement()
}
}
2
3
4
5
6
7
8
9
差异类型:
- props 改变 → patchProps
- children 改变 → patchChildren
- 文本 → patchText
# 🔥 6. Vue3 最重要的优化:patchFlags(编译器生成)
Vue3 与 React 最大区别之一:编译器对 diff 的提前优化。
例如:
<div :id="dynamic" class="static">Hello</div>
编译后 render:
return (openBlock(), createElementBlock(
"div",
{
id: dynamic
},
"Hello",
8 /* PROPS */,
["id"]
))
2
3
4
5
6
7
8
9
其中:
- patchFlag = 8 (PROPS)
→ 表示仅 props 变化、并且只有
"id"动态
Vue runtime 就能做到:
只 patch "id",不 diff 其他属性 不 diff class(静态) 不 diff children(静态)
📌 Vue3 静态提升与 patchFlag 优化使它的渲染性能远超 React 的纯 VDOM diff。
# 🧱 7. 静态提升(hoist static)
如果有静态节点:
<div><span>static</span></div>
它会被提升到渲染函数外:
const _hoisted_1 = /*#__PURE__*/ createVNode("span", null, "static");
return () => (
createVNode("div", null, [_hoisted_1])
)
2
3
4
5
静态节点不参与 diff! 这是 Vue 3 最大的性能优势。
# 🍃 8. Fragment / Teleport / Suspense 的渲染机制
# Fragment
一个组件可以返回多个根节点,内部 patch 时特殊处理多个 children。
# Teleport
渲染时不在父组件中操作,而是把 DOM 直接移动到指定容器。
# Suspense
处理异步组件渲染,fallback → resolve → patch。
# 🚀 9. Vue3 渲染流程总览图(非常关键)
template
↓
compiler-dom
(静态提升 + patchFlags)
↓
render()
↓
createVNode()
↓
effect()
(初次渲染收集依赖)
↓
patch()
/ | \
mount diff update props
↓
update DOM
数据变化 → trigger → effect → patch → DOM 更新
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
你看完这个就已经对 Vue3 渲染机制有框架级理解了。