官方解释:
-
预期:
number | string | boolean (2.4.2 新增) | symbol (2.5.12 新增)
key
的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
最常见的用例是结合
v-for
:<ul> <li v-for="item in items" :key="item.id">...</li> </ul>
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
- 完整地触发组件的生命周期钩子
- 触发过渡
例如:
<transition> <span :key="text">{{ text }}</span> </transition>
当
text
发生改变时,<span>
总是会被替换而不是被修改,因此会触发过渡。
举个例子:
没有加key值:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<div id="app">
<div>
<input type="text" v-model="name" >
<button @click="add">添加</button>
</div>
<ul>
<li v-for="(item, i) in list">
<input type="checkbox"> {{item.name}}
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
newId: 3,
list: [
{ id: 1, name: '我是小米' },
{ id: 2, name: '我是华为' },
{ id: 3, name: '我是苹果' }
]
},
methods: {
add() {
//注意这里是unshift
this.list.unshift({ id: ++this.newId, name: this.name })
this.name = ''
}
}
});
</script>
</body>
</html>
当选择小米时,添加oppo后选择却变成了oppo,我们想要的是当添加oppo后,一种选中的是依然是小米
添加key值后
同样当选中小米时,添加oppo后依旧选中的是小米。
你认为添加了oppe,实际上是 小米--》oppo,华为---》小米,苹果--》华为,添加一个苹果。
只是将小米修改成了oppo,选中框依然复用小米的。如果添加:key。会将整个列表重新渲染
,也可参考,https://www.zhihu.com/question/61064119
key的作用就是更新组件时判断两个节点是否相同。相同就复用,不相同就删除旧的创建新的。带唯一key时每次更新都不能找到可复用的节点,不但要销毁和创建vnode,在DOM里添加移除节点对性能的影响更大。所以会才说“不带key可能性能更好”。
作者:玲.海
链接:https://www.zhihu.com/question/61064119/answer/1774180312
// 增删dataList列表项
vm.dataList = [3, 4, 5, 6, 7] // 数据进行增删
// 1. 没有key的情况, 节点位置不变,内容也更新了
[
'<div>3</div>', // id: A
'<div>4</div>', // id: B
'<div>5</div>', // id: C
'<div>6</div>', // id: D
'<div>7</div>' // id: E
]
// 2. 有key的情况, 节点删除了 A, B 节点,新增了 F, G 节点
<div v-for="i in dataList" :key='i'>{{ i }}</div>
[
'<div>3</div>', // id: C
'<div>4</div>', // id: D
'<div>5</div>', // id: E
'<div>6</div>', // id: F
'<div>7</div>' // id: G
]
从以上来看,不带有key,节点位置不变,可以更有效的复用节点,带key在增删节点上有耗时,没有实现节点复用,不但要销毁和创建vnode,还要在DOM里添加移除节点,对性能的影响更大。
那官方为什么要推荐带key?
带上唯一key虽然会增加开销,但是对于用户来说基本是无感知的,而且能保证组件状态正确。
举个例子:一个新闻列表,可点击列表项来将其标记为"已访问",可通过tab切换“娱乐新闻”或是“社会新闻”。
不带key属性的情况下,在“娱乐新闻”下选中第二项然后切换到“社会新闻”,"社会新闻"里的第二项也会是被选中的状态,因为这里复用了组件,保留了之前的状态。要解决这个问题,可以为列表项带上新闻id作为唯一key,那么每次渲染列表时都会完全替换所有组件,使其拥有正确状态。