开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
文章首发于语雀,如有问题欢迎评论指正,感谢!
在Vue文档中关于v-for指南模块有这么一段话:
那什么是就地更新策略呢?我们先来写一个案例,通过案例来介绍。
const app = {
template: `
<ul>
<li v-for="(item, index) of list">
<span>{{ item.value }}</span>
<button @click="delteItem(index)">Del</button>
</li>
</ul>`,
data(){
return{
list: [
{
id: 1,
value: "item-1"
},
{
id: 2,
value: "item-2"
},
{
id: 3,
value: "item-3"
}
]
}
},
methods: {
delteItem(index) {
this.list.splice(index, 1);
}
}
}
以上代码,实现了一个简单的列表,然后通过按钮可以进行删除某项,效果如下:
点击删除 DOM 的变化
当我们删除item-2的时候看看会发生什么?
从上面的动态图中我们可以看到:我们删除的是item-2的li,第二个li里面的内容变成了item-3的内容,实际上删除的是第三个li(浏览器中紫色闪烁表示dom的内容发生了变化)。
这就是Vue的就地更新策略,回头看Vue文档的那句话:
Vue将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。也就是说默认的情况下Vue会尽量使用已经存在的DOM元素,直接在已有的DOM上进行复用修改,这样可以带来一定性能上的提升。
看一个更明显的案例:
const app = {
template: `
<div>
<div v-if="isLogin">
<span>欢迎</span>
<a href="javascript:;" @click="isLogin = false">xiechen</a>
</div>
<div v-else>
<a href="javascript:;" @click="isLogin = true">登录</a>
<a href="javascript:;">注册</a>
</div>
</div>`,
data(){
return{
isLogin: false
}
}
}
以上代码,两个模块里都有a标签,按照我们的理解当条件发生变化的时候,div都会重新渲染,实际上Vue会进行就地更新策略。
可以很明显的看到第二个a标签一直在闪烁,也就是内容一直在更新而不是销毁重新创建的a标签!!!
就地更新的缺陷
再次回到Vue文档的那句话:
这又是什么意思呢?同样的我们还是用动态图要进行演示,我们把第一个案例进行改造,给每个li都新增一个input输入框:
<ul>
<li v-for="(item, index) of list">
<span>{{ item.value }}</span>
<input type="text" />
<button @click="delteItem(index)">Del</button>
</li>
</ul>
实际的效果有点让人疑惑,我明明删除的是item-2,为什么item-3的输入框内容却发生了变化?
这其实就是「就地更新」的缺陷!!!
因为input输入框是一个临时的状态,Vue无法判断节点的value到底有什么用,所以在删除item2的时元素会进行复用,input里的值也是会被保留的,实际删除的是第三个li及第三个li内的input。
如何进行解决?
现在的问题就是Vue不会根据最新的顺序去更新DOM,而是用已有的DOM进行属性的修改。
在这种情况下,我们需要给li标签绑定一个key属性,这样Vue就会根据最新的数据对DOM进行调整,而它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。
可以简单认为key是给每一个DOM节点一个唯一标识,这样Vue就不会启用就地更新了。
<ul>
<li v-for="(item, index) of list" :key="item.id">
<span>{{ item.value }}</span>
<input type="text" />
<button @click="delteItem(index)">Del</button>
</li>
</ul>
从图片中可以看到,加上key属性后item-2删除后,item-2的input也被删除啦。
key 的作用
简单说key的作用主要是为了更高效的对比虚拟DOM中每个节点是否是相同节点;
举个简单的例子:三胞胎战成一排,你怎么知道谁是老大?如果老大皮了一下子,和老三换了一下位置,你又如何区分出来?给他们挂个牌牌,写上老大、老二、老三。这样就不会认错了,key就是这个作用。
所以在使用
key属性的时候需要注意,key属性必须是唯一的,不变的!当数据更新的时候,Vue可以通过key属性去确认元素,同时确认子元素是否要进行更新。