静态提升是编译期将纯静态节点及属性提取为常量,标记-1跳过diff,复用同一VNode对象;满足内容与结构均不可变的节点(如<h2>关于我们</h2>)被标记isStatic:true,其createVNode调用移至顶层,运行时直接引用。

静态提升的核心,是让编译器在模板编译阶段就识别出“永远不变”的内容,并把它从每次执行的渲染函数中剥离出来,只创建一次、反复复用。
编译期识别纯静态节点
Vue 3 编译器会逐层扫描 AST,判断一个节点是否满足两个硬性条件:内容不可变(无 {{ }}、无 :class、无 v-if 等指令)、结构不可变(不会被条件或列表控制显隐或增删)。只有完全静态的节点,比如 <h2>关于我们</h2> 或 <span class="label">状态</span>,才会被打上 isStatic: true 标记。
- 纯文本、固定 class/style、无属性绑定的标签,基本都能被识别
- 只要出现一个响应式变量、哪怕只是
:id="id",整个节点就失去提升资格 - 子节点全静态,父节点才可能被整体提升;任一子节点动态,父节点也会降级为动态
提升为常量 VNode 并打上 -1 标志
被标记为静态的节点,会在编译输出中变成顶层常量声明,例如:
const _hoisted_1 = /*#__PURE__*/ createVNode("h2", null, "关于我们", -1)
这里的 -1 是 PATCH_FLAG_TEXT,表示该 VNode 是纯静态、不可补丁更新的。它不是运行时判断的结果,而是在生成 JS 代码时就固化下来的字面量对象。
- 这个对象在模块加载时就创建完成,所有组件实例共享同一份引用
- 渲染函数内部不再调用
createVNode构造它,而是直接引用_hoisted_1 -
/*#__PURE__*/提示打包工具可安全移除该语句(如果未被引用)
运行时跳过创建与 Diff,但不跳过挂载流程
静态提升不是“跳过渲染”,而是精准减少冗余操作:
- 每次 render 执行,都不再重复调用
createVNode创建相同结构 - 在 patch 阶段,遇到 flag 为 -1 的节点,diff 算法直接跳过比对,复用原 VNode
- 它仍参与组件挂载、卸载、父级 block 更新等流程,只是内部不可变
- 内存中只存一份,多个组件实例、多次重渲染都指向同一个对象
静态属性也能被单独提升
不只是整棵节点树,连 class、style 这类静态属性也会被抽离成常量对象:
const _hoisted_2 = { class: "btn primary" }
渲染时通过 _mergeProps 合并动态属性,避免每次拼接对象开销。
- 像
<button class="btn" :disabled="loading">中的class="btn"就会被提取 - 但
class="btn {{ status }}"或:class="[a, b]"则无法拆分,整体会退化为动态 - 这种细粒度提升进一步压缩了对象创建和属性合并的成本


















