patchflags.keyed_fragment 是 vue3 编译器为带 key 的 v-for 或多根节点结构标记的优化标识,触发时运行时调用 patchkeyedchildren 函数,通过双端比对、key 映射与最长递增子序列实现精准复用与移动,避免全量重建;其有效性依赖稳定唯一 key(如 item.id),而非常规 index。

PatchFlags.KEYED_FRAGMENT 是 Vue 3 编译器在生成虚拟节点(VNode)时,为带 v-for 且含有 :key 的多子节点结构打上的优化标记。它的核心作用是告诉运行时:这个 fragment 的子节点具备唯一标识,可以启用「基于 key 的精准复用」策略,避免全量比对和 DOM 重建。
什么时候会触发 KEYED_FRAGMENT?
只要满足以下任一条件,编译器就会将该 fragment 的 patchFlag 设为 KEYED_FRAGMENT:
-
v-for指令渲染的列表,且每个子节点绑定了明确、稳定的:key(如:key="item.id") - 多个根节点的模板(如 `` 包裹多个同级元素),且显式使用了
key属性 -
<slot></slot>插槽出口中动态渲染多个具名插槽,且插槽内容带key
它如何影响 patch 过程?
当 runtime 遇到 patchFlag & PatchFlags.KEYED_FRAGMENT 为真时,会跳过默认的线性遍历逻辑,转而调用 patchKeyedChildren() 函数。该函数采用「双端+映射索引」策略:
- 先从头部开始逐个比对新旧节点的
key,相同则复用并更新;遇到第一个不匹配就停止前向扫描 - 再从尾部反向比对,同样只处理
key相同的节点 - 剩余未比对的节点,构建旧节点
key → oldVNode映射表 - 遍历剩余新节点,用
key查表复用;查不到则创建新节点;旧节点中未被复用的会被卸载
为什么必须用稳定 key?
KEYED_FRAGMENT 的有效性高度依赖 key 的稳定性:
- 若用
:key="index",数组顺序变化会导致 key 错位,旧节点被错误复用或销毁,引发状态错乱(如输入框失焦、动画中断) - 理想 key 应来自数据本身唯一且不变的标识,例如
user.id、todo.uuid - key 不仅用于 diff,也参与组件实例生命周期管理——相同 key 对应同一组件实例,不同 key 触发全新挂载
与 UNKEYED_FRAGMENT 的关键区别
没有 :key 的 v-for 或多根节点,会被标记为 UNKEYED_FRAGMENT,此时运行时只能按顺序逐个比对:
- 新旧节点长度相同时,依次 patch;任意一处不匹配,后续全部强制更新
- 新节点更长,追加剩余节点;旧节点更长,批量移除多余节点
- 完全无法识别“移动”操作,比如
[a,b,c]→[c,a,b]会被当作三个替换 + 两个删除 + 两个新增,而非三次移动










