跳绳鸭
67.76M · 2026-02-04
假设我们要渲染一个简单的待办事项列表:
<div id="app">
<div v-for="item in list">
<input type="checkbox">
<span>{{ item.text }}</span>
</div>
</div>
当我们删除中间某个项目时,你可能会发现复选框的状态出现了错误。选中的项目被删除了,但其他项目的选中状态却乱了套。
Vue在更新DOM时,会尽量复用已有的元素。这是一种优化策略,可以减少DOM操作,提高性能。
但是,当数据顺序发生变化时,Vue需要知道哪些元素可以复用,哪些需要重新创建。如果没有key,Vue只能按照顺序进行对比。
没有key的情况:
key给每个节点一个唯一标识。Vue通过这个标识来跟踪每个节点的身份。
<!-- 正确的写法 -->
<div v-for="item in list" :key="item.id">
<input type="checkbox">
<span>{{ item.text }}</span>
</div>
加上key之后:
要理解key的重要性,我们需要了解Vue的虚拟DOM机制。
虚拟DOM是真实DOM的JavaScript对象表示。Vue通过对比新旧虚拟DOM的差异,来决定如何更新真实DOM。
Vue使用Diff算法来比较虚拟DOM的差异。这个算法会找出最小的变更,然后应用到真实DOM上。
没有key的Diff过程:
有key的Diff过程:
选择合适的key很重要。不合适的key可能带来问题。
// 好的例子
const list = [
{ id: 1, text: '学习Vue' },
{ id: 2, text: '写代码' },
{ id: 3, text: '阅读文档' }
]
// 不好的例子 - 使用索引作为key
<div v-for="(item, index) in list" :key="index">
// 不好的例子 - 使用随机数作为key
<div v-for="item in list" :key="Math.random()">
当列表需要排序时,key的作用特别明显。
// 初始列表
[
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' },
{ id: 3, name: '橙子' }
]
// 排序后
[
{ id: 3, name: '橙子' },
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' }
]
有key时,Vue知道这是元素位置的移动,而不是内容的修改。
过滤列表时,key确保正确的元素被保留或移除。
在动态组件中,key可以强制组件重新创建:
<component :is="currentComponent" :key="componentKey">
改变componentKey会触发组件的重新渲染。
在某些简单场景下,不加key可能不会立即发现问题:
但为了代码的健壮性,建议始终加上key。
有些开发者会这样使用key:
<!-- 错误:使用索引作为key -->
<div v-for="(item, index) in list" :key="index">
<!-- 错误:使用不稳定的值作为key -->
<div v-for="item in list" :key="Math.random()">
这些用法都会导致各种奇怪的问题。
当列表发生变化时,索引也会变化。原来索引为1的元素,在删除前面的元素后,可能变成索引0。这会导致Vue错误地复用元素。
在同一个v-for中唯一即可,不需要全局唯一。
如果数据源没有提供唯一标识,可以考虑:
理解key的作用,能帮助我们写出更稳定、性能更好的Vue应用。这个看似小的细节,在实际开发中却很重要。
下次使用v-for时,记得给它一个合适的key。