patchKeyedChildren是Vue3 runtime-core内部处理带key子节点更新的核心函数,通过双端预处理、新增挂载、多余卸载及中间复用四步实现高效DOM复用与移动。

patchKeyedChildren 是什么
它不是 Vue3 的公开 API,而是 runtime-core 内部用于更新带 key 的动态列表的核心函数。当你在模板里写 v-for="item in list" :key="item.id",Vue 在比对新旧子节点时,就会调用它来执行高效复用和移动逻辑。
为什么必须用 key?它到底解决什么问题
没有 key 时,Vue 默认使用“就地更新”策略:新旧节点按索引一一对应,直接 patch。这在简单场景下快,但遇到插入、删除、排序等操作,会频繁触发不必要的 DOM 更新甚至状态错乱(比如 input 失焦、组件重渲染)。
加了 key 后,Vue 就能基于唯一标识做语义化比对——相同 key 的节点尽可能复用,只更新 props 或 children;不同 key 的才创建或卸载。而 patchKeyedChildren 就是实现这个语义比对的“大脑”。
它的核心四步流程(不看源码也能懂)
函数接收新旧两组子节点(VNode 数组),通过四轮扫描完成比对:
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
立即学习“前端免费学习笔记(深入)”;
- 从头开始对齐相同 key 的节点:依次比较 oldStart 和 newStart,key 相同则复用并递进指针;否则跳出
- 从尾开始对齐相同 key 的节点:比较 oldEnd 和 newEnd,同样复用 + 收缩边界;直到头尾交叉或 key 不匹配
- 处理剩余新节点(新增):若 newStart ≤ newEnd,说明有新元素没被匹配,逐个创建挂载
- 处理剩余旧节点(删除/移动):若 oldStart ≤ oldEnd,说明有旧元素多余;此时构建 key → oldIndex 的映射表,再遍历剩余新节点,查表决定复用还是移动
关键细节:移动操作怎么判断?为什么有时 DOM 会乱序
移动不是靠“位置差”,而是靠 新序列中节点的相对顺序。函数内部维护一个 lastIndex,记录已处理新节点在旧列表中出现的最大索引。当发现当前新节点的旧索引 小于 lastIndex,说明它在旧列表里本该更靠前,现在却排在后面——那就得把它 插入到当前 anchor 前面(即执行 move)。
常见乱序原因:key 值重复、key 动态计算不稳定(比如用 index 当 key)、数据源本身未保持稳定引用。这些都会导致映射失效,让 Vue 误判为“新增+删除”,而非“移动”。

















