使用v-for
更新已渲染的元素列表时,列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改则重新渲染这一项,否则复用之前的元素。我们在使用的使用经常会使用index
(即数组的下标)来作为key,
但其实这是不推荐的一种使用方法,有时也可能出现问题,原因如下:
在数组中插入一条数据:
const list = [ { id: 1, name: 'test1', }, { id: 4, name: '我是插队的那条数据', } { id: 2, name: 'test2', }, { id: 3, name: 'test3', }, ]
<div v-for="(item, index) in list" :key="index" >{{item.name}}</div>
此时除了第一个数据可以复用之前的之外,另外三条数据都需要重新渲染,导致性能下降:
之前的数据 之后的数据 key: 0 index: 0 name: test1 key: 0 index: 0 name: test1 key: 1 index: 1 name: test2 key: 1 index: 1 name: 我是插队的那条数据 key: 2 index: 2 name: test3 key: 2 index: 2 name: test2 key: 3 index: 3 name: test3
下面的例子是出现问题的:
<div id="app"> <div> <input type="text" v-model="name"> <button @click="add">添加</button> </div> <ul> <li v-for="(item, index) in list" :key="index"> // v-for不添加key或者key赋值为索引都会有问题 <input type="checkbox"> {{item.name}} </li> </ul> <script> // 创建 Vue 实例,得到 ViewModel 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> </div>
当选中吕不为时,添加楠楠后选中的确是李斯,并不是我们想要的结果,我们想要的是当添加楠楠后,选中的还是吕不为
加了具有唯一性的key的checkbox跟内容进行了一个关联,会达到我们想要的效果:
<li v-for="(item, i) in list" :key="item.id"> <input type="checkbox"> {{item.name}} </li>
vue和react的虚拟DOM的Diff算法大致相同,首先看一下diff算法的处理方法,对操作前后的dom树同一层的节点进行对比,一层一层往下对比,如下图:
比如下边这种情况,我们希望可以在B和C之间加一个F:
Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,这样很没有效率。所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
因为vue组件采用高度复用,增加Key可以标识组件的唯一性,这样是为了高效的更新虚拟DOM。同理在react中使用map渲染列表时,也是必须加key,且推荐做法也是使用id
,也是这个原因。
原文: https://www.jianshu.com/p/4bd5e745ce95
https://segmentfault.com/a/1190000013810844?utm_source=tag-newest