Vue-v-for列表渲染中的key

在上一章讲到 v-for  列表渲染的博文中,只是说到了 v-for  的基本使用,并没有对其内部进行更深层次的 解读,其实在 v-for  这个指令下,有一个及其关键的 连带属性 key。这个 key 才是 Vue 或者是是 MVVM 框架的 最精髓的东西。

key的使用方式:以数组为例

  • {{person.name}}

和之前相比,发现有什么不同了么?没错,就是在循环标签体中加上了  :key='index'  ,正是这个玩意,完成了 MVVM 框架在改变数据之后的高效渲染。

首先,这个key前面有一个冒号,代表的是使用 v-bind 这个指令动态绑定的。

然后这个key绑定的值,需要是唯一的,就是你遍历之后,每个li节点上的key都是不同的,在这个简单例子中,我们可以直接使用 index 来作为 key 的绑定值。

  • {{person.name}}

 Vue-v-for列表渲染中的key_第1张图片

输出之后能看到在DOM节点上,key这个属性是不存在的,因为这个属性是给Vue使用的,所以不会暴露出来,如果你自己写个自定义属性,例如:a='1' 那么还是会展示出来的。

  • {{person.name}}

 

 如果你说你要是不动态绑定,你就要写死,就要直接 key='1',那我也没话说,直接在控制台上见真章吧。

  • {{person.name}}

Vue-v-for列表渲染中的key_第2张图片

根据谷歌翻译,这个错误是:检测到重复键:“1”。 这可能会导致更新错误。 

这是个啥子意思呢?重复键又是个啥玩意?怎么就导致更新错误了?杠精直接发起了夺命三连问。

在 解决这些问题之前,我们先来说一下,使用 index 作为 key 的绑定值的弊端在哪。然后再来了解 这个 key 到底是用来干什么的,这样的话,上面的问题就迎刃而解了。

index的弊端:性能开销大,数据对应错误(破坏数据原有顺序)

 如果单纯的是上面的展示信息,代码是没有问题的,但是,如果我想在数据中添加一条数据的话,就会出现状况了。

首先,向数组中添加数据的话,有两种情况,第一种是加到最后,第二种是加到最前。

加到最后是正常的,加到最前就会有比较诡异的情况了

性能开销大 这个 问题暂时不太好演示,留下下文搞个大点的例子再来说。先说数据对应错误这个东西。

步骤1、在 li 节点里面添加一个 input 框

Vue-v-for列表渲染中的key_第3张图片

步骤2、然后在 input 框里面输入数据

Vue-v-for列表渲染中的key_第4张图片

步骤3、点击按钮之后,添加一个新的 person 对象到 数组里面去,重新渲染之后再来看页面展示 ,这里就要分为两种情况了,

        第一种,push到数组末尾,这种情况展示下来是没有问题的,因为添加到数组末尾,是没有打乱整个数组排序的,所以展示没有错乱

add() {
  const a = { id: 3, name: '赵六' }
  this.personArr.push(a)
}

 Vue-v-for列表渲染中的key_第5张图片

         第二种,unshift到数组首位,这样问题就来了,因为打乱了原有排序,v-for的时候,根据key 来处理数据循环渲染时,就会出现这种问题

Vue-v-for列表渲染中的key_第6张图片

 这个时候就能看到,数据对应错误了,这就是使用 index 作为 关键字 key 的绑定值的弊端。

虚拟DOM中key的作用 

 首先,key 的作用是用来作为 diff 算法的唯一比对标识的。通过 diff 算法对比 新旧虚拟DOM,然后根据对比结果开始渲染页面。

简单描述一下 diff 算法的对比过程。就拿上面的 index 作为key值 的例子来说。

Vue-v-for列表渲染中的key_第7张图片

步骤1:通过初始数据,生成 【初始虚拟DOM】,然后直接渲染成【真实DOM】展示在页面上。

步骤2:改变数据之后,在数组最前添加一条数据,打乱了数据原有排序,且此时仍旧使用index 作为 key 的值。此时,根据【新数据】,生成了【新的虚拟DOM】节点。然后将【新的虚拟DOM】节点与【初始虚拟DOM节点】对比。 

步骤三:

        (1)、首先在新的虚拟DOM节点列表取出第一条虚拟DOM,和旧的虚拟DOM节点列表对比。先根据 key 来对比,发现 两条数据的 key 都是 0,然后接着对比内部元素,发现 文本节点(赵六-张三)不匹配,所以生成新的真实文本DOM节点。

        (2)、接着对比 标签节点(input),因为是虚拟DOM,所以 只比对标签,不比对标签内部value值发现标签节点是一致的,所以 真实的input DOM节点 复用了。真实input节点复用了,那么input内部的value值也复用了,所以造成了节点数据展示错位。

        (3)、如果最开始就发现 key 值 不一样,那么这条虚拟DOM 则不用进行比对了,直接根据新的虚拟DOM生成新的真实DOM,不存在复用的情况了。以此对比,一条条虚拟DOM对比过后,就生成了 新的真实DOM。

步骤四:diff 对比完成之后,能复用的DOM节点就直接复用了,不能复用的,生成新的真实DOM节点,然后渲染到页面上。

 ps1:如果是使用数据中的 唯一标识来指定 key 值,那么对比之后,会发现只有新生成的虚拟DOM节点,需要生成新的真实节点,其余的虚拟DOM节点,则是完全相同,可以直接复用,极大的提高了渲染效率

ps2:如果 在遍历的时候,不写key,那么Vue在遍历的时候,默认会把 index 作为 key 的绑定值。

本章小结

首先,key 是只存在于虚拟DOM中的。 是提供给Vue内部使用的,真实DOM节点上是不存在这个属性的。

虚拟DOM中key的作用:这个key绑定的值就相当于是这个节点的 唯一编码,就像我们的身份证号一样,是唯一识别码。当数据发生变化时,Vue 会根据 【新数据】生成 【新的虚拟DOM节点】,随后,根据 diff 算法,对比【旧的虚拟DOM】和 【新的虚拟DOM】,生成真实DOM节点。

diff 对比规则:

1、【旧虚拟DOM】中找到了与【新虚拟DOM】 相同的 key   

    (1)、若是虚拟DOM中的内容没变,则直接复用之前的真实DOM节点

    (2)、若是虚拟DOM中的内容改变,则生成新的真实DOM节点,然后替换之前的真实DOM节点

2、 【旧虚拟DOM】中没有找到与【新虚拟DOM】 相同的 key 

    (1)、直接创建真实DOM,并且渲染到页面上 

3、使用 index 作为 key值,可能会引发的问题

    (1)、若是对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新===> 界面效果展示没问题,但是渲染效率低下

      (2)、若是结构中还包含 输入类 DOM ( form 表单类元素):则会产生错误的DOM更新 ===> 导致界面渲染错误

4、开发阶段如何选择 key 值?

        (1)、最好使用每条数据的唯一标识作为key,例如:id、身份证号码等等

        (2)、如果对不存在的数据进行逆序添加,逆序删除等破坏顺序的操作,如果仅仅用于展示,那么 使用 index 作为 key 值是没有问题的。

你可能感兴趣的:(vue专栏,vue.js,前端,javascript)