PatchFlags.HOISTED 是值为-1的特殊标记,用于标识完全静态节点;编译器在AST解析中判定节点无任何动态内容后将其提升至render函数外并标记HOISTED,运行时直接跳过该节点及其子树的diff和patch,实现零开销复用。

PatchFlags.HOISTED 是什么
HOISTED 是 Vue 3 编译器为**完全静态的节点**打上的特殊标记,值为 -1。它不表示“需要更新某部分”,而是直接告诉运行时:“这个节点从不变化,连 diff 都不用进,跳过即可”。它不是动态更新标记,而是一种跳过参与更新流程的指令。
它怎么被生成出来的
编译器在解析模板 AST 时,会对每个节点做静态性判定。只要一个节点满足以下全部条件,就会被标记为 HOISTED:
- 所有属性都是字面量(如
id="app"、class="header"),不含任何响应式变量或表达式 - 子内容是纯文本,且不含插值(如
<p>Hello World</p>),或子节点本身也全是静态节点 - 没有绑定事件(
@click)、指令(v-if、v-for)、插槽或动态 prop - 父级上下文未引入任何动态影响(比如没被包裹在
v-if块中)
满足后,该节点会被提前“提升”(hoist)到 render 函数外部,只创建一次,后续渲染复用同一个 VNode 实例。
它在运行时如何起作用
当 patch 过程走到某个 VNode 时,会先检查 patchFlag:
- 如果是
-1(HOISTED),运行时直接跳过整个节点,不比对 props、不递归 children、不调用任何 patch 子函数 - 该节点对应的 DOM 也不会被重新设置属性或文本——因为根本没动它
- 其子树中所有节点也一并跳过,形成“静态区块”的天然边界
这相当于把一段 HTML 冻结成常量,彻底移出更新链路,节省了内存分配、属性遍历、DOM 属性写入等全部开销。
和 StaticHoisting 的关系
HOISTED 标记与静态提升(Static Hoisting)是一体两面:
- HOISTED 是标记:写在 VNode 上,供运行时读取判断
- StaticHoisting 是行为:编译器在生成 render 函数时,把被标记的节点提取到函数体外,变成一个 const 变量
例如模板:<div class="logo"><h1>My App</h1></div>,编译后类似:
const hoisted = createVNode('div', { class: 'logo' }, [createVNode('h1', null, 'My App')], -1)
return function render() {
return createBlock('div', null, [hoisted])
}
这里 hoisted 就是被提升的静态节点,它的 patchFlag: -1 确保每次 render 都不会重建或 patch 它。

















