v-for中key的作用与原理

一、虚拟DOM中key的作用

key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue会对新虚拟DOM与旧虚拟DOM的差异进行比较。

二、如何选择key

最好使用每条数据的唯一标识作为key,用一个简单的例子说明:

1.用index作为key时

点击按钮在列表最前方添加赵六用户

  <ul>
      <li v-for="(p,index) of persons" :key="index">
        {{p.name}}
        <input type="text">
      </li>
      <br>
      <button @click="Add">在最前方添加一个用户</button>
  </ul>
 data () {
    return {
      persons: [
        {id: '01', name: '张三'},
        {id: '02', name: '李四'},
        {id: '03', name: '王五'}
      ]
    }
  },
  methods: {
    Add () {
      let p = {id: '04', name: '赵六'}
      this.persons.unshift(p)
    }
  }

点击以后,页面如下图
image

然而,如果在我点击按钮前,在输入框中输入一些内容
image

点击按钮后就会变成
image
很明显,这并不是我们理想中想要呈现的效果。

2.用id作为key时

<ul>
   <li v-for="p of persons" :key="p.id">
      {{p.name}}
      <input type="text">
   </li>
   <br>
   <button @click="Add">在最前方添加一个用户</button>
</ul>

在输入框中输入与之前相同的内容,点击按钮后这次的页面则变成了下图
image
很明显,这次就对了!

三、原因分析

为什么用id和index作为key出来的效果天差地别呢,首先来分析一下key的作用原理。

用index作为key时:

image

首先会根据初始数据生成虚拟DOM,然后将虚拟DOM转为真实DOM,在加入新数据以后,再根据新数据生成新的虚拟DOM,此时Vue并不会再重新将新虚拟DOM直接转为真实DOM,而是进行一个虚拟DOM的对比算法。如下:

image

首先在新的虚拟DOM中按照顺序取出第一项,然后根据标识“key=0”在旧的虚拟DOM中寻找拥有一样“key=0”的节点,然后开始挨个对比。

image

第一个节点为文本节点,Vue发现一个为张三一个为赵六,不一致,于是将新的文本节点赵六转为真实DOM

image

然后来到第二个标签节点input,需要注意的是,我们对文本框的输入是在真实DOM中操作的,但在虚拟DOM中两边的标签节点input是一样的,所以这时候Vue不会将它重新转成真实DOM,而是直接复用左边的。

image

以此类推,key等于1和等于2时,文本节点重新转为真实DOM,标签节点复用。

image

当来到key等于3这一项时,发现左边并没有key是等于3的一项,所以这个时候,Vue直接将右边key等于3这一项直接转为真实DOM。

用id作为key时:

image

首先也是按照顺序取出第一项,然后根据标识“key=04”在左边寻找拥有同样key的一项,发现没有,于是直接转为真实DOM。

image

然后按顺序取出第二项,根据标识“key=01”,在左边寻找也是“key=01”的一项,挨个对比文本节点和标签节点,发现两个节点都完全一样,所以直接复用之前的真实DOM。

image

以此类推,李四和王五都是直接复用左边的真实DOM。

四、总结

  1. 用index作为key可能会引发的问题:若对数据进行逆序添加、逆序删除等破坏顺序的操作时,会产生没有必要的真实DOM更新,此时界面效果没有问题,但效率太低。
  2. 在开发中如何选择key:最好使用每条数据的唯一标识作为key,比如id、身份证号、手机号等,如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
posted @ 2022-11-04 11:14  leayun  阅读(435)  评论(1编辑  收藏  举报