前端面试宝典

Vue 中 key 的原理(结合你的代码详解)

你现在的代码用索引 index 作为 key,会出现数据错乱、输入框内容不匹配的 Bug,我用最通俗的方式给你讲清 key 的底层原理、为什么会出问题、以及正确用法。

一、先搞懂:Vue 为什么需要 key

Vue 在渲染列表(v-for)时,会做虚拟 DOM 对比(Diff 算法)

  1. 数据变化时,Vue 不会直接重新渲染所有 DOM,而是生成新虚拟 DOM
  2. 用**key** 作为唯一标识,对比新旧虚拟 DOM
  3. 相同 key = 复用 DOM不同 key = 新建/删除 DOM

核心作用精准标识列表项,提升渲染效率,保证 DOM 与数据一一对应


二、你的代码为什么会出 Bug?

你的代码:

<li v-for="(p,index) of persons" :key="index">

数组索引 indexkey,并且用了 unshift()头部添加数据

1. 初始状态(key = 索引)

索引 indexkey数据输入框内容
00张三-18输入框A
11李四-19输入框B
22王五-20输入框C

2. 点击添加(头部插入老刘)

数组变成:[老刘, 张三, 李四, 王五]

Vue 对比 key 时发现:

  • key=0:原本是张三 → 现在变成老刘 → 复用 DOM,只改文本,不改输入框
  • key=1:原本是李四 → 现在变成张三 → 复用 DOM
  • key=2:原本是王五 → 现在变成李四 → 复用 DOM
  • key=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 的底层规则

  1. key 是虚拟 DOM 的唯一标识,给 Diff 算法提供匹配依据
  2. 相同 key:Vue 认为是同一个节点,复用 DOM(优化性能)
  3. 不同 key:Vue 会销毁旧 DOM,新建 DOM
  4. 禁止滥用 index 作为 key
    • 列表逆序添加/删除/排序时,一定会出 Bug
    • 列表项包含输入框、复选框等可交互元素时,必错乱
  5. 最佳实践:用数据的唯一 id(如 iduuid

五、修复后的完整代码

<!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>

总结

  1. key 原理:作为虚拟 DOM 的唯一标识,让 Vue 精准复用/更新 DOM
  2. 错误用法key="index"(列表变动会导致数据与 DOM 错位)
  3. 正确用法key="唯一id"(保证数据和 DOM 永久一一对应)
  4. 触发场景:只要列表会增删改、排序,绝对不能用 index 做 key