下面按编译器视角给出判定规则(Vue 3):
- 静态节点(不会参与更新)
- 纯静态 HTML:不含 mustache 插值、无 v- 指令、无 :/@ 绑定。
- 所有属性均为字面量(如 class="a"、style="color:red")。
- 子树也必须全静态,编译器会整棵“静态提升”(hoist),更新时完全跳过。
- 动态节点(会被收集进 block 的 dynamicChildren)
- 动态文本/插值:{{ msg }} → TEXT
- 动态类/样式::class="x"、:style="y" → CLASS/STYLE
- 动态属性::id="x"、v-bind="obj" → PROPS/FULL_PROPS
- 事件绑定:@click="onClick"(值变化需 patch)
- 表单与双向绑定:v-model
- 条件与循环:v-if/else-if/else、v-for → 产生动态 Fragment(KEYED/UNKEYED/STABLE)
- 动态组件与异步组件:<component :is="Comp">、defineAsyncComponent
- 插槽(含依赖响应式或带 slot props):→ DYNAMIC_SLOTS
- 特殊容器:Teleport、KeepAlive 内部多为动态子树
- 实用判断(经验法则)
- 模板里只要出现 {{}}、v- 指令、:/@、或结构指令(v-if/v-for),基本就是动态。
- 完全没有上述元素且子节点也满足,则是静态,可被整体 hoist。
- 编译产物侧标识
- 有 PatchFlag(如 TEXT/CLASS/PROPS…)→ 动态。
- 标记为 HOISTED 的 vnode/子树 → 静态,更新跳过。