Skip to content

Vue 中 key 的作用

key 是 Vue 的一个特殊 attribute,主要用于 Vue 的虚拟 DOM 算法,在新旧节点对比(Diff 算法)时辨识 VNodes。

1. 核心作用:Diff 算法的标识

在没有 key 的情况下,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法(就地更新策略)。

而当使用了 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除/销毁 key 不存在的元素。

场景 1:v-for 列表渲染 (最常见)

vue
<ul>
  <li v-for="item in items" :key="item.id">
    {{ item.text }}
  </li>
</ul>
  • 为什么要用 ID 而不是 Index? 如果使用 index 作为 key,当列表顺序发生变化(如在头部插入一项)时,index 会发生错位。Vue 会认为旧的 index 0 变成了新的 index 0(实际上内容变了),导致就地复用,这可能会引发以下问题:
    1. 性能损耗:虽然 DOM 节点复用了,但内容要全部更新。
    2. 状态错乱:如果列表项中有<input>或子组件维持了内部状态,状态会保留在原来的 index 位置,导致数据和 UI 不匹配。

场景 2:强制替换元素/组件

如果你想强制触发生命周期钩子,或者触发过渡动画,可以改变 key

vue
<!-- 当 text 变化时,<span> 会被销毁并重新创建 -->
<!-- 这会触发进入/离开的过渡动画 -->
<transition>
  <span :key="text">{{ text }}</span>
</transition>
vue
<!-- 当 id 变化时,Component 会被销毁并重新创建 -->
<!-- 完整的生命周期钩子(created, mounted 等)会重新执行 -->
<Component :key="id" />

2. 原理简述

在 Diff 算法中,Vue 会通过 key 生成一个 Map 映射。

  • 无 key:O(n) 遍历查找,或直接就地复用(可能出错)。
  • 有 key:O(1) 直接通过 Map 找到对应的旧节点。

3. 总结

  1. 准确性:避免就地复用带来的状态 bug(特别是在表单输入、组件状态场景)。
  2. 性能:帮助 Diff 算法更快地找到对应的节点,减少不必要的 DOM 操作(虽然创建销毁有开销,但相比错误的 DOM 更新,逻辑更正确)。
  3. 功能:用于强制触发生命周期或动画。

最佳实践:在 v-for 中始终使用唯一 ID 作为 key,尽量避免使用 index。