咱们可以把 key 理解成列表里每个元素的 “名字牌”,作用是让 Vue 能清清楚楚认出谁是谁,避免搞错。
先看个生活例子:
假设你在班里管理 3 个同学的作业本,分别是小明、小红、小刚的。
- 没有 “名字牌”(key)的情况:你只按位置记:第 1 本是小明的,第 2 本是小红的,第 3 本是小刚的。突然,小红和小刚换了座位,你还是按位置看,就会把小刚的作业本当成小红的,完全搞错了。
- 有 “名字牌”(key)的情况:每个作业本上都写了名字(小明、小红、小刚)。不管他们怎么换座位,你只要看名字就知道 “这本是小红的,那本是小刚的”,绝对不会乱。
Vue 里的 key 就是这个道理
Vue 渲染列表时,会生成虚拟的 DOM 节点。当列表数据变化(比如增删、排序),Vue 需要对比新旧列表,决定哪些节点要保留、哪些要修改。
- 没有
key:Vue 就按 “位置” 对比,可能把 A 的节点错当成 B 的来复用,导致数据和节点对不上(比如输入框内容乱跳)。 - 有
key:Vue 会按key这个 “名字牌” 精准匹配,相同key的节点直接复用,不同的才重新创建,既准确又高效。
具体案例:为什么不能用索引当 key?
假设有个待办列表,用索引 index 当 key:
vue
<!-- 初始列表 -->
<ul>
<li v-for="(item, index) in list" :key="index">
<input type="checkbox"> {{ item.name }}
</li>
</ul>
// 数据
list = [
{ name: '吃饭' },
{ name: '睡觉' },
{ name: '打游戏' }
]
此时 key 是 0、1、2,对应 “吃饭”“睡觉”“打游戏”。如果你勾选了 “睡觉”(第 2 项,key=1),然后删除第 1 项 “吃饭”,列表变成:
// 新数据
list = [
{ name: '睡觉' },
{ name: '打游戏' }
]
这时新列表的 key 变成 0、1,Vue 会认为:
- 原来
key=0的 “吃饭” 被删了 - 原来
key=1的 “睡觉” 现在变成key=0了 - 原来
key=2的 “打游戏” 现在变成key=1了
结果就是:你勾选的 “睡觉” 会莫名其妙跑到 “打游戏” 前面,因为 Vue 按 key 复用了节点,位置乱了。
正确做法:用唯一不变的 id 当 key
vue
<ul>
<li v-for="item in list" :key="item.id"> <!-- 用id当key -->
<input type="checkbox"> {{ item.name }}
</li>
</ul>
// 数据(每个item有唯一id)
list = [
{ id: 1, name: '吃饭' },
{ id: 2, name: '睡觉' },
{ id: 3, name: '打游戏' }
]
这时每个元素的 key 是 1、2、3(永远不变)。就算删除第 1 项,新列表的 key 是 2、3,Vue 能精准匹配到原来的 “睡觉” 和 “打游戏”,勾选状态也不会乱。
总结
key 就是列表元素的 “唯一名字牌”,让 Vue 不会因为位置变化认错元素。记住两点:
- 别用索引当
key(位置会变,名字牌就失效了); - 最好用数据自带的唯一
id当key(像身份证号一样稳定)。