可以唯一的确定一个DOM元素,让diff算法更加高效
<body>
<div id='app'>
<p v-for='item in items' :key='item'>{{item}}</p>
</div>
<script>
var vm = new Vue({
el:'#app'
data:{
items:['a','b','c','d','e']
}
mounted(){
setTimeout(()=>{
// 在c的前边添加一个f
this.items.splice(2,0,'f')
},2000)
}
})
</script>
</body>
上边案例重现的是以下过程
不使用key,则 diff 算法默认是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率? 更新了3次,之后做了一次创建插入的操作
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
只使用了一次创建追加的操作
使用key
//首次循环 patch A
A B C D E
A B F C D E
//第二次循环 patch B
B C D E
B F C D E
//第三次循环 patch E(首位找到相同节点)
C D E
F C D E
//第4次循环 patch D
C D
F C D
//第5次循环 patch C
C
F C
//oldCh全部处理结束,newCh中剩下F,创建F并插入到C前边
结论:
key 的作用主要是 为了实现高效的更新虚拟 DOM,提高性能。其原理是vue在patch的过程中通过key可以精准的判断两个节点是否是同一个,从而避免频繁的更新元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
另外,若不设置key,还可能在列表更新时引发一些隐蔽的bug。例如:
点击第二项的delete,
原因很简单,你认为你删除了2,但Vue会认为你做了两件事:
- 把2变成了3
- 然后把3删除了
- vue在使用相同的标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
借用官方文档上的例子:
<transition>
<span :key="text">{{text}}</span>
</transition>
这里如果text发生改变,整个<span>元素会发生更新,因为当text改变时,这个元素的key属性就发生了改变,在渲染更新时,Vue会认为这里新产生了一个元素,而老的元素由于key不存在了,所以会被删除,从而触发了过渡。
假如没有key属性:
<transition>
<span>{{text}}</span>
</transition>
那么当text改变时,Vue会复用元素,只改变<span>元素的内容,而不会有新的元素被添加进来,也不会有旧的元素被删除。
同理,key属性被用在组件上时,当key改变时会引起新组件的创建和原有组件的删除,此时组件的生命周期钩子就会被触发。