patchflags 是 vue 3 编译器在模板编译阶段为 vnode 打上的位掩码数字标记,用于运行时精准识别需更新的属性类型(如 text=1、class=2),跳过静态部分实现靶向更新。

Patch Flags 是 Vue 3 编译器在模板编译阶段,为虚拟节点(VNode)自动打上的数字标记,本质是一个位掩码(bitmask)。它不靠运行时猜测,而是在生成 render 函数时就写死在 createVNode 调用里,直接告诉渲染器:“这个节点哪些部分会变,更新时只查这里,其余全跳过”。
它是怎么标记动态性的?
编译器逐行扫描模板,识别响应式绑定的位置,并按类型分配对应标志:
- {{ msg }} → 只影响文本内容 → 标记为 1(TEXT)
- :class="{ active: isActive }" → 只影响 class → 标记为 2(CLASS)
- :style="{ color: textColor }" → 只影响内联样式 → 标记为 4(STYLE)
- :id="uid" :data-tip="tip" → 多个普通响应式属性 → 合并为 8(PROPS)
- 多个动态类型共存(如文本 + class)→ 按位或组合,例如 1 | 2 = 3,运行时用
&运算快速拆解
静态内容怎么处理?
完全不依赖响应式数据的节点,会被标记为 -1(HOISTED):
- 比如
<p>欢迎光临</p>这类纯静态文本,编译后直接提升(hoist),生成一次后复用 - 运行时 diff 遇到
patchFlag === -1,连子节点都不进,整棵树跳过比对 - 这和动态节点形成明确分界:静态归静态,动态标清楚,互不干扰
渲染器如何靠它做靶向更新?
更新触发时,渲染器不再递归遍历整个 VNode 树,而是根据 patchFlag 值直接分支执行:
- 看到 1 → 只执行
el.textContent = next.children,不碰 props、不查 style、不比事件 - 看到 2 → 只调用
patchClass(el, prev, next),跳过所有其他属性更新逻辑 - 看到 -1 → 完全跳过该节点及其全部子树,连是否需要更新都不判断
- 看到 16(FULL_PROPS) → 表明 props 结构可能变化(比如 key 或 v-if 切换),才走更重的完整比对流程
怎么确认它真起作用了?
不需要猜,三步就能验证:
- 打开 Vue Devtools → 切到 “Compiler Output”,找组件的
render()函数,搜索createVNode,看第四个参数(如createVNode('div', null, children, 2)中的 2) - 开发环境下,在组件中打印
console.log(this.$.subTree.patchFlag),查看根节点标记 - 修改响应式数据后观察 DOM 变化范围——只有被标记的部分更新,其余保持原样










