shapeflags 是 vue 3 中用位掩码标识 vnode 类型与特征的整数,通过位运算(如 | 和 &)高效组合与判断节点类型(如 element、stateful_component),兼顾性能、内存与扩展性。

Vue 3 的 VNode 通过 shapeFlags 字段用位掩码(bitmask)高效标识节点类型和特征,避免冗余字段和条件判断。理解其位运算逻辑,是读懂源码、调试渲染流程、自定义渲染器的关键。
ShapeFlags 是什么?为什么用位运算?
shapeFlags 是一个整数,每个二进制位代表一种节点“形状”(如是否为元素、组件、文本、Fragment 等)。Vue 定义了一系列常量(如 ELEMENT = 1 、<code>STATEFUL_COMPONENT = 1 ),通过左移生成互不重叠的标志位。多个类型可同时存在(比如一个有状态组件也可能是 Suspense 的子节点),用按位或(<code>|)组合;判断是否包含某类型则用按位与(&)。
好处是:内存占用小、判断极快(单次位运算)、支持类型叠加、便于枚举和扩展。
核心 ShapeFlags 常量及含义
以下为 Vue 3.4 源码中关键标识(路径:packages/shared/src/shapeFlags.ts):
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
-
ELEMENT = 1(二进制
0001):原生 DOM 元素,如<div>、<code><span></span> - STATEFUL_COMPONENT = 1 (
0010):带 setup / data / methods 的 Options API 或 Composition API 组件 - FUNCTIONAL_COMPONENT = 1 (
0100):纯函数式组件(无状态、无实例) - TEXT_CHILDREN = 1 (
1000):children是字符串(非数组或 null) - ARRAY_CHILDREN = 1 :
children是 VNode 数组 - SUSPENSE = 1 :Suspense 节点
- TELEPORT = 1 :Teleport 节点
- FRAGMENT = 1 :Fragment 节点(
<template></template>) - 判断是否为组件:
vnode.shapeFlags & COMPONENT(COMPONENT = STATEFUL_COMPONENT | FUNCTIONAL_COMPONENT) - 判断是否为普通元素:
vnode.shapeFlags & ELEMENT - 判断 children 类型:
if (vnode.shapeFlags & TEXT_CHILDREN) { ... }或if (vnode.shapeFlags & ARRAY_CHILDREN) { ... } - 判断是否为高阶容器:
if (vnode.shapeFlags & (TELEPORT | SUSPENSE | FRAGMENT)) { ... } - 创建复合节点:
createVNode(Component, null, 'hello', shapeFlags: STATEFUL_COMPONENT | TEXT_CHILDREN)
注意:一个组件节点的 shapeFlags 可能同时含 STATEFUL_COMPONENT | TEXT_CHILDREN(如返回字符串的 setup 组件),或 TELEPORT | ARRAY_CHILDREN(Teleport 包含多个子节点)。
常见位运算操作与实战判断
源码中高频出现以下模式,直接对应实际需求:
这种写法比用字符串类型字段(如 type: 'component')或对象属性(isComponent: true)更轻量,且编译时可静态分析优化。
与 PatchFlags 的区别与协作
别混淆 shapeFlags 和 patchFlags:
- shapeFlags 描述“**这是什么类型的节点**”(宏观结构);
- patchFlags 描述“**这个节点哪些部分需要更新**”(微观 diff 策略,如 TEXT、PROPS、HYDRATE_EVENTS)。
二者正交:一个 shapeFlags = ELEMENT 的 <div> 节点,其 <code>patchFlags 可能是 0(全量 diff)或 2(仅需 patch props)。
渲染器先看 shapeFlags 分支进入不同处理逻辑(如 processElement vs processComponent),再根据 patchFlags 在内部跳过无需更新的子流程。










