一、v-for
官方介绍:
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
我们都知道在使用v-for时,应该搭配上一个key属性,经常直接使用index来作为key,但是这样是存在问题的。
二、实例
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="index">
{{item.value}}
<input type="text">
</li>
</ul>
<button @click="remove">移除</button>
</div>
let app = new Vue({
el: '#app',
data:{
list:[
{id: '1', value: 'value_1'},
{id: '2', value: 'value_2'},
{id: '3', value: 'value_3'}
]
},
methods:{
remove(){
this.list.shift();
}
}
})
点击移除按钮前:
点击移除按钮:
3、解析
为什么会出现上述问题呢?
这里就要涉及虚拟DOM和diff算法了。
简单的来说就是diff算法比较是,如果虚拟dom(对象)具有key属性,那么新旧dom对比时,会比较key,如果相同,则比较内容,将新内容赋值给虚拟dom,而不会去重新构造新的虚拟dom。
删除vlaue1所在dom节点后,vlaue2对应的index变为1,value3对应的index变为2,因为key和index是对应的。
那么就出现上述渲染结果。
diff算法比较时,发现key为1的虚拟dom所对应的value变为2了,所以将第一个虚拟dom的value值改为2,同你将key为2的值变为3,发现新dom节点没有key为3的,所以就认为删除了第三个dom节点
。
所以使用index作为key是不合适的,因为虽然index和当前的循环结果唯一对应,但是如果不按顺序删除或者增添元素,那么更改后的index又会对应新的节点,这也是为什么能使用随机数当作key的原因,原理是一样的。
应该使用循环的数组中对应唯一的属性最为key,比如id。