Vue 中 key 的原理是什么?

在 Vue 中,`key` 是一个特殊的属性,通过唯一标识追踪 vnode 的身份,优化 diff 算法以高效更新 DOM。

Vue 困难 Virtual DOM diff算法 虚拟DOM

在 Vue 中,key 是一个特殊的属性,其核心原理是通过唯一标识追踪虚拟 DOM(vnode)的身份,优化 Vue 的 diff 算法,以实现高效的 DOM 更新。具体原理如下:

一、核心原理

  1. 唯一标识 vnode
    key 为每个 vnode 分配一个稳定的唯一标识符。当数据变化触发重新渲染时,Vue 的 diff 算法会通过 key 精准匹配新旧 vnode:
    • 相同 key:复用原有真实 DOM,仅更新变化部分(如属性或内容)。
    • 不同 key:销毁旧节点,创建新节点并插入到 DOM 中。
  2. 优化 diff 算法复杂度
    未使用 key 时,Vue 会采用“就地复用”策略(就地复用),即认为相同索引位置的元素是同一个节点,可能导致错误复用(如列表顺序变化时状态错乱)。
    使用 key 后,算法复杂度从 O(n³) 降至 O(n)
    • 通过 key 建立映射表,跳过无变化节点的比较。
    • 仅对有变化的部分进行 DOM 操作(移动、更新或删除)。
<!-- 示例:列表渲染时推荐稳定 key -->
<ul>
  <li v-for="item in items" :key="item.id"></li>
</ul>

二、解决的问题

  1. 状态错乱
    当列表中元素顺序变化时(如排序、增删),未使用 key 可能导致输入框内容错位、动画失效等问题。key 确保元素身份独立,避免旧 DOM 的残留状态被错误复用。

  2. 性能损耗
    “就地复用”策略可能引发非必要的 DOM 更新或全量刷新。通过 key 精准定位变更节点,减少无效 DOM 操作。

三、最佳实践

  1. 必须稳定且唯一
    • ✅ 使用不可变唯一标识:如数据 ID、手机号(:key="item.id")。
    • ❌ 避免索引(index):索引变化会使 Vue 错误复用节点(例如插入数据时,原索引对应元素错位)。
  2. 特殊场景强制更新
    为组件设置 key 并绑定动态值(如时间戳),可强制组件销毁并重建以触发生命周期钩子:
<Component :key="Date.now()" />

四、底层机制:patch 算法

updateChildren 方法中,Vue 通过 key 调用 sameVnode 函数判断新旧 vnode 是否为同一节点:

function sameVnode(a, b) {
  return a.key === b.key && /* 其他条件(如标签名) */
}

若匹配失败,则重新创建节点而非复用。