vnode是vue中描述dom结构的轻量级javascript对象,包含type、props、children、key、el、shapeflag等关键字段,经render和patch流程映射为真实dom,再由浏览器完成layout与paint。

Vue 的 DOM 构建不是直接操作真实节点,而是先生成 VNode,再由渲染器将其转化为浏览器可识别的 DOM 结构。这个过程不涉及浏览器原生的“渲染树(Render Tree)”概念——那是浏览器自身在解析 HTML/CSS 后构建的内部结构,与 Vue 的虚拟 DOM 层级无关。Vue 的 VNode 是对 DOM 的轻量级 JavaScript 描述,它最终被 patch 算法驱动,映射为真实 DOM 节点,再交由浏览器完成后续的 Layout、Painting 等原生渲染流程。
VNode 是什么,它包含哪些关键信息
VNode(Virtual Node)是一个普通 JavaScript 对象,描述一个 DOM 元素应有的状态和结构。它不是真实节点,也不具备 DOM 方法,但包含了渲染所需的核心字段:
- type:节点类型,可以是字符串(如 'div')、组件对象、Fragment 或 Teleport 等特殊类型
- props:归一化后的属性对象,含 class、style、事件监听器(on: { click: handler })、指令绑定等
- children:子节点数组,每个子项也可能是 VNode、字符串(文本)、或 null/undefined
- key:用于 diff 算法中标识节点身份,影响复用逻辑
- el:挂载后指向对应的真实 DOM 元素,初始为 null
- shapeFlag:位标记,快速区分节点类型(如是否为组件、是否带 v-if、是否静态等),提升运行时判断效率
从 VNode 到真实 DOM 的转换靠 render + patch
Vue 不直接把 VNode “画”出来,而是通过平台专属的渲染器(renderer)执行两步关键操作:
- render(vnode, container) 是入口函数,首次调用时传入根 VNode 和挂载容器(如 #app),内部触发 patch(null, vnode, container)
- patch 是核心补丁函数:当 oldVNode 为 null,表示首次挂载,走创建分支;否则对比新旧 VNode,执行最小化更新(diff + 更新 DOM 属性/子节点/事件等)
- 创建阶段会递归调用 createElm:对每个 VNode 创建真实元素(document.createElement)、设置属性(el.setAttribute)、插入子节点(el.appendChild),并把 el 挂回 VNode.el 字段
- 遇到组件 VNode 时,不直接创建 DOM,而是调用 createComponentInstance 实例化组件,并递归执行其自身的 mount 流程
Vue 的 VNode 树 ≠ 浏览器的 Render Tree
这是常被混淆的关键点:
- Vue 的 VNode 树是框架层抽象,完全由 JavaScript 维护,用于跨平台(Web / 小程序 / SSR)和高效更新
- 浏览器的 Render Tree 是渲染引擎内部产物,由 DOM 树 + CSSOM 合并生成,只包含需要绘制的可见节点及其样式计算结果(display !== none、visibility !== hidden 等)
- Vue 只负责把 VNode 映射为 DOM 节点并插入 document;之后浏览器自动将这些节点纳入自己的 DOM 树,再触发样式计算、布局(Layout)、绘制(Paint)等原生流程
- 也就是说:VNode → DOM(Vue 控制)→ DOM 树 → Render Tree → Layout → Paint(浏览器控制)
模板如何变成 VNode:编译环节不可跳过
如果你写的是 <template><div>{{ msg }}</div></template>,VNode 并非手动生成,而是经过标准编译流水线:
- Template → AST:字符串模板被解析为抽象语法树,保留结构但不含运行时逻辑(例如 v-if 节点被标记为 condition,但不执行判断)
-
AST → 渲染函数:遍历 AST,拼接 JS 字符串,再用 new Function() 动态生成 render 函数(如
return h('div', [ctx.msg])) - 渲染函数 → VNode:组件实例调用 render(),内部调用 h()(即 createElement),按参数构造出标准 VNode 对象
- 若你手写
setup() { return () => h('div', 'hello') },就跳过了前两步,直接进入第三步
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











