Vue 3 的 PatchFlags 是编译器自动注入 VNode 的数字标记,用于运行时跳过不必要的 diff:TEXT(1)、CLASS(2)、STYLE(4)、PROPS(8)、FULL_PROPS(16)、NEED_PATCH(32)、HOISTED(-1),支持按位或组合。

Vue 3 的 PatchFlags 是编译阶段注入到虚拟节点(VNode)上的数字标记,用于在运行时跳过不必要的 diff 比较,大幅提升更新性能。它不是手动设置的,而是由 Vue 编译器(@vue/compiler-dom)根据模板结构自动推导生成。理解每种标志位的含义,能帮你读懂生成的渲染函数、定位性能瓶颈,甚至写出更友好的优化型模板。
文本内容变化:TEXT
当一个元素的子节点仅为纯文本,且该文本是响应式变量(如 {{ msg }})时,会打上 1(PatchFlags.TEXT)。此时 patch 过程只需更新 node.textContent,无需遍历子节点或比对 VNode 结构。
- 适用场景:
<div>{{ title }}</div> - 不触发:静态文本(
<div>Hello</div>)、含插槽或组件子节点
类名动态绑定:CLASS
当 class 绑定为响应式对象或表达式(如 :class="{ active: isActive }" 或 :class="cls"),且不是全静态时,会标记 2(PatchFlags.CLASS)。运行时仅更新 node.className 或操作 classList,跳过属性 diff 全量比对。
- 注意:字符串拼接(
:class="'base ' + (isActive ? 'active' : '')")也会触发,但可能生成更复杂的 patch 逻辑 - 静态 class(
class="btn")不参与 patch,编译期直接写死
内联样式变化:STYLE
使用 :style 绑定响应式样式对象(如 :style="{ color: textColor, fontSize: size + 'px' }")时,生成 4(PatchFlags.STYLE)。patch 阶段只更新 node.style 对象属性,避免对整个 style 字符串做 diff 或重写。
立即学习“前端免费学习笔记(深入)”;
- 支持对象语法和数组语法(含 CSS 变量)
- 静态
style="color: red"不打 flag,直接固化在 VNode props 中
动态属性绑定(非 class/style):PROPS
当存在响应式的非专有属性(比如 :id、:data-id、:aria-label 等),且未被归类到 CLASS/STYLE/TEXT 中时,会用 8(PatchFlags.PROPS)。此时只比对并更新「有响应式绑定的那些属性」,而非全部 props。
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
- 例如:
<input :id="inputId" :disabled="isDisabled" value="static" />→ 只 patchid和disabled - 不包括
class、style、onXXX事件(它们有独立 flag 或走 event 处理路径)
具有 key 的动态子节点:FULL_PROPS
当一个元素同时满足两个条件:① 有响应式绑定的非 class/style 属性;② 子节点含 v-if、v-for 或插槽内容(即子节点结构可能动态变化),就会升级为 16(PatchFlags.FULL_PROPS)。这意味着不能只 patch 单个属性,需进入完整 props diff 流程(但仍跳过 children diff,除非 children 也带 flag)。
- 常见于封装组件:
<MyList :items="list" :loading="isLoading" />,其中MyList模板内部有 v-for - 本质是「props 变化可能影响子节点渲染逻辑」,所以需更谨慎地处理 props 更新
动态子节点(v-if / v-for / 插槽):NEED_PATCH
值为 32(PatchFlags.NEED_PATCH),表示该 VNode 的子节点需要运行时 diff —— 常见于有 v-if 分支、v-for 列表、或作用域插槽的容器节点。它本身不描述“怎么 patch”,而是告诉 runtime:“别跳过 children,老老实实比一遍”。
- 例如:
<ul v-if="items.length"><li v-for="i in items">{{ i }}</li></ul>→ ul 节点带 NEED_PATCH - 注意:单个
v-if容器若子节点全是静态,可能被进一步优化掉(如提升为 Block)
静态节点提升:HOISTED
HOISTED(值为 -1)不是传统 PatchFlag,而是一个特殊标记,表示该 VNode 在编译期已被提升(hoist)为模块级常量,**运行时完全不参与 patch**。它是性能优化的终点形态之一。
- 触发条件:节点完全静态(无插值、无指令、无动态属性)且不依赖任何响应式状态
- 例如:
<h1>Welcome</h1>、<span class="icon"></span> - 在生成的 render 函数中可见
_hoisted_1这类变量
组合型标志位与按位或运算
PatchFlags 支持叠加,用二进制按位或(|)组合。例如一个带动态 class、动态 style 和 v-if 的 div,flag 可能是 2 | 4 | 32 = 38。runtime 通过 flag & PatchFlags.CLASS 判断是否需处理 class。
- 常见组合:
TEXT | CLASS = 3(文本+类名都动态) - 查看方式:在浏览器中打印组件的 render 函数,搜索
createVNode调用,观察第 4 个参数(flags) - 工具推荐:Vue Devtools 的「Performance」面板可高亮带 flag 的节点
理解 PatchFlags 不是为了手写 flag,而是读懂 Vue 的优化意图——哪些地方它敢跳过,哪些地方它必须深挖。写模板时保持结构清晰、减少跨层级响应式依赖、合理拆分组件,就是在配合这些标志位发挥最大效力。

















