patchflag.text(值为1)标记纯响应式文本更新,仅执行textcontent赋值;patchflag.class(值为2)标记动态class绑定,仅调用patchclass更新classlist;二者可按位或组合(如3),运行时精准分支处理,跳过无关diff。

PatchFlag.TEXT 和 PatchFlag.CLASS 是 Vue 3 编译器最常打上的两类动态标记,它们分别对应文本内容与 class 属性的响应式更新场景。理解二者差异,能帮你写出更利于编译器优化的模板,也能快速定位渲染性能瓶颈。
TEXT 标记:只动文字,不动结构
当一个元素的子节点是纯响应式文本(如 {{ msg }}),且不含插槽、组件或其它动态子节点时,编译器会为该 VNode 打上 PatchFlags.TEXT(值为 1)。
- 运行时 patch 阶段仅执行
el.textContent = next.children,不比对 props、不遍历子节点、不检查事件监听器 - 静态文本(如
<div>Hello</div>)不会触发 TEXT 标记,它被静态提升或直接固化在 VNode 中 - 若文本中混入插值+静态内容(如
Hello {{ name }}!),整个字符串仍视为动态文本,仍打 TEXT 标记 - 一旦子节点包含任何非文本内容(比如
v-if、<slot></slot>、<mycomp></mycomp>),TEXT 就失效,可能升级为FULL_PROPS或走全量 diff
CLASS 标记:精准操作 classList
当 :class 绑定的是响应式值(对象、数组或表达式),且不是完全静态时,编译器生成 PatchFlags.CLASS(值为 2)。
- 运行时只调用
patchClass(el, prev, next),内部通过el.className或el.classList增删切换,跳过 style、attrs、子节点等所有无关比对 - 字符串拼接写法(如
:class="'btn ' + (active ? 'primary' : '')")也会触发 CLASS,但可能生成更复杂的 patch 逻辑(如需解析空格分隔) - 纯静态 class(
class="btn submit")不参与运行时更新,编译期直接写死,无 flag - 若同时有 class 变化和文本变化(如
<div :class="cls">{{ title }}</div>),flag 值为1 | 2 = 3,运行时按位与分别处理两类更新
怎么一眼识别它们是否生效?
打开 Vue Devtools → Compiler Output 面板,找 createVNode 调用:
-
createVNode("p", null, toDisplayString(msg), 1 /* TEXT */)→ TEXT 生效 -
createVNode("div", { class: ["base", cls] }, null, 2 /* CLASS */)→ CLASS 生效 - 数值后带的注释(如
/* TEXT */)是编译器自动生成的可读提示,运行时只认数字
常见误用与优化建议
- 避免在 class 绑定里频繁计算:如
:class="getClasses()"每次都返回新数组,会强制重设 classList;改用计算属性缓存 - 不要把文本插值和 v-html 混用:含
v-html的节点无法打 TEXT 标记,会降级为FULL_PROPS或BAIL - 多个响应式 class 条件,优先用对象语法
:class="{ active, disabled: !ready }",比三元拼接更易被编译器识别为 CLASS - 若文本和 class 都动态,但彼此独立,无需额外操作——Vue 自动组合 flag,运行时并行处理,互不干扰










