组件VNode与元素VNode的核心差异在于是否参与自身挂载逻辑及拥有独立响应式上下文与生命周期:前者是待实例化的模板描述,触发子实例创建与生命周期;后者直连DOM,无实例、无生命周期,由父级patch直接操作。

Vue.js 的渲染机制中,组件 VNode 和元素 VNode 的核心差异不在于“是否可复用”,而在于是否参与自身挂载逻辑、是否拥有独立的响应式上下文与生命周期。理解这点,才能准确把握它们在 patch 过程中的行为分叉。
组件 VNode:自带挂载入口与独立实例
组件 VNode(如 生成的 VNode)本质是一个“待实例化模板描述”。它不直接映射到真实 DOM 节点,而是携带以下关键信息:
-
组件选项或定义(
componentOptions),含 props、slots、自定义事件等配置; -
占位标记(
isComponent: true或componentInstance === null初始态); - 在
patch阶段,若发现是组件 VNode 且尚未挂载,会调用createComponent创建子实例,并执行其$mount流程(可能触发beforeMount→render→mounted); - 后续更新时,只触发子组件内部的响应式更新和 re-render,父组件 patch 不直接操作其内部 DOM —— 即“更新边界”由组件实例自身控制。
元素 VNode:直连 DOM 的最小渲染单元
元素 VNode(如 或 Hello)是对原生 DOM 节点的轻量抽象,特点是:
- 包含明确的
tag(如'div')、data(attrs/class/style 等)、children(子 VNode 数组); - 在
patch中直接对应createElement、createTextNode或cloneNode等 DOM 操作; - 无生命周期,不创建实例,属性变更(如
class、style)由 patch 算法直接 diff 并同步到真实节点; - 作为组件 VNode 的子节点时,它只是被“托管”渲染,自身不干预父组件的更新节奏。
关键差异场景举例
假设父组件中同时存在:
- A:
→ 组件 VNode; - B:
→ 元素 VNode。
当 value 变化时:
- A 触发
MyInput实例内部的 prop 更新 + 自身 re-render,可能伴随updated钩子; - B 由父组件 patch 直接更新 input 的
value属性,无额外实例开销,也无钩子介入; - 若
MyInput内部也是用原生实现,则它的元素 VNode 更新发生在子组件自己的 patch 阶段,与父级完全隔离。
性能与设计意图的底层呼应
Vue 将组件 VNode 设计为“更新隔离单元”,既保障了状态封装性,也支持细粒度更新优化(例如 shouldUpdate 或 memo);而元素 VNode 是渲染树的“叶子节点”,追求零抽象开销。二者协同构成“组件树→VNode 树→DOM 树”的三级映射,缺一不可。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











