Vue 中 key 的原理(结合你的代码详解)
你现在的代码用索引 index 作为 key,会出现数据错乱、输入框内容不匹配的 Bug,我用最通俗的方式给你讲清 key 的底层原理、为什么会出问题、以及正确用法。
一、先搞懂:Vue 为什么需要 key?
Vue 在渲染列表(v-for)时,会做虚拟 DOM 对比(Diff 算法):
- 数据变化时,Vue 不会直接重新渲染所有 DOM,而是生成新虚拟 DOM
- 用**
key** 作为唯一标识,对比新旧虚拟 DOM - 相同
key= 复用 DOM,不同key= 新建/删除 DOM
核心作用:精准标识列表项,提升渲染效率,保证 DOM 与数据一一对应。
二、你的代码为什么会出 Bug?
你的代码:
<li v-for="(p,index) of persons" :key="index">
用数组索引 index 做 key,并且用了 unshift() 从头部添加数据。
1. 初始状态(key = 索引)
| 索引 index | key | 数据 | 输入框内容 |
|---|---|---|---|
| 0 | 0 | 张三-18 | 输入框A |
| 1 | 1 | 李四-19 | 输入框B |
| 2 | 2 | 王五-20 | 输入框C |
2. 点击添加(头部插入老刘)
数组变成:[老刘, 张三, 李四, 王五]
Vue 对比 key 时发现:
key=0:原本是张三 → 现在变成老刘 → 复用 DOM,只改文本,不改输入框key=1:原本是李四 → 现在变成张三 → 复用 DOMkey=2:原本是王五 → 现在变成李四 → 复用 DOMkey=3:新增 → 新建 DOM
✅ 结果:输入框和数据错位了!这就是 index 作为 key 的致命问题。
三、正确的 key 应该用什么?
必须用列表项的【唯一、固定、不变】标识(比如后端返回的 id)。
修改你的代码:
<!-- key 改为唯一 id,不要用 index -->
<li v-for="p of persons" :key="p.id">
为什么用 id 就没问题?
id是数据自带的唯一值,数据变,id 永远不变- Vue 能精准识别每个列表项,DOM 和数据完全绑定
- 头部插入数据时,不会复用错误的 DOM,输入框不会错乱
四、总结:key 的底层规则
key是虚拟 DOM 的唯一标识,给 Diff 算法提供匹配依据- 相同
key:Vue 认为是同一个节点,复用 DOM(优化性能) - 不同
key:Vue 会销毁旧 DOM,新建 DOM - 禁止滥用 index 作为 key:
- 列表逆序添加/删除/排序时,一定会出 Bug
- 列表项包含输入框、复选框等可交互元素时,必错乱
- 最佳实践:用数据的唯一 id(如
id、uuid)
五、修复后的完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../tools/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表(遍历数组)</h2>
<button @click.once="add">添加一个老刘</button>
<ul>
<!-- 唯一修改:key 用 p.id -->
<li v-for="p of persons" :key="p.id">
{{p.name}}-{{p.age}}
<input type="text" />
</li>
</ul>
</div>
</body>
<script>
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '李四', age: 19 },
{ id: '003', name: '王五', age: 20 },
],
},
methods: {
add() {
const p = { id: '004', name: '老刘', age: 40 }
this.persons.unshift(p)
},
},
})
</script>
</html>
总结
key原理:作为虚拟 DOM 的唯一标识,让 Vue 精准复用/更新 DOM- 错误用法:
key="index"(列表变动会导致数据与 DOM 错位) - 正确用法:
key="唯一id"(保证数据和 DOM 永久一一对应) - 触发场景:只要列表会增删改、排序,绝对不能用 index 做 key