目录
1.暴露问题,使用index作为key
2.使用唯一标识p.id作为key
3.不写key的配置
4.key的工作原理及虚拟DOM的对比算法
5.总结
25.Vue列表渲染_爱米酱的博客-CSDN博客这一节开始我们来学一下Vue中与列表渲染相关的东西,这部分知识很重要,而且还比较多,所以我就拆成几个小节来讲。那么这一小节我们就先讲讲基本列表,把基本列表讲清楚之后,我们再讲key的原理,列表过滤和列表排序实现效果:讲到这里这个遍历就已经实现了,但是这里还有一个特别重要的属性,就是key,我们这里不详谈这个属性,这一节我们只关注怎么配置这个属性即可,具体的深入分析内容会在下一节呈现。和key相关的内容我们可以在Vue官网的学习-->API中找到。 这个key属性就是给遍历的每一项加了一个特殊标识,虽然https://blog.csdn.net/qq_37050372/article/details/125595515在上一节中我们讲了简单的Vue的列表渲染,那么这一节中我们就详细的探讨一下在Vue中当我们使用v-for去渲染一个列表的时候,我们传递的key有什么作用?它的原理又是什么样的?这一节也会把大家关心的几个点讲清楚,也是面试中经常会问的。1.在Vue中这个key写了它会怎么处理?要是不写Vue又会怎么处理?2.如果使用了key,那么key的值使用什么好?是使用遍历时候得索引值比较好?还是使用每个值的唯一标识id比较好?这个其实也是分情况的。接下来我们都会说明。
列表渲染
人员列表
- {{p.name}} -- {{p.age}}
在上一节的这段代码中我们最终采用的是使用index作为遍历的key(索引值),那么针对目前的这个功能来说是没问题的。
这里我们粗略的给大家说一下这个key有什么作用?这个key就是给节点一个标识,相当于人类社会中的身份证号。
接下来为了让大家理解的更加透彻,我将会通过一个反例来暴露出不使用key或者使用了不合适的key会有什么样的问题,然后再给出解决办法的方式帮助大家理解。
上一节课中,我们这个代码实现效果是这样的,那么为了暴露问题,我们这里需要再实现一个需求。点击按钮,在张三的前面添加一个老六节点。
这里补充一个知识点:
- push()方法可以在数组的末属添加一个或多个元素
- shift()方法把数组中的第一个元素删除
- unshift()方法可以在数组的前端添加一个或多个元素
- pop()方法把数组中的最后一个元素删除
列表渲染
人员列表
- {{p.name}} -- {{p.age}}
实现效果:
这里值得注意的一个点是,我们在写模板的时候每个li都写了一个属性key,值就是遍历时候的索引值index,但是页面上生成的可用的真实DOM,却都不再拥有key属性。这是为什么呢?
这是因为这个key属性是Vue内部在使用的,我们模板上的确写了key属性,而Vue也的确用了,但是Vue在使用完之后,生成真实DOM的时候就把key去掉了。
接着说,刚刚我们实现了在张三前面添加一个老六的功能,虽然表面上看着一点问题也没有,但是它其实是存在很严重的效率问题的。后面我们会证明这个问题的存在的。
1.暴露问题,使用index作为key
接下来我们让每个人的li中,都有一个input框,用于输入各自的信息,然后重新实现刚刚添加老六的效果。我们期望的效果是添加完老六之后,它所对应的li后面会生成一个空的input框
列表渲染
人员列表
- {{p.name}} -- {{p.age}}
实现效果:
我们可以看到这个时候诡异的事情出现了。在添加完老六之后,他们四个人后面跟着的input框出现了错位。
写到这里我就把我想要暴露的问题给大家呈现出来了?那么这个问题是怎么造成的呢?这个问题错就错在它在这种特殊的情况下使用了index作为key。这个时候有人就会有疑问,这是什么特殊情况呀?
2.使用唯一标识p.id作为key
那么接下来我们换一种写法,我们不使用index作为key,而是使用p.id,也就是每行值的唯一标识作为key,看看会不会再出现这样的问题?
列表渲染
人员列表
- {{p.name}} -- {{p.age}}
实现效果:
从上面的效果来看,我们用每行的唯一标识作为key是正常的。
3.不写key的配置
那如果我们连key都不写了,又会是什么样的效果呢?我们再试试
列表渲染
人员列表
- {{p.name}} -- {{p.age}}
实现效果:
我们可以看到不使用key,也会有问题。
4.key的工作原理及虚拟DOM的对比算法
综上所述,我们可以看到,当我们使用index作为key,或者不使用key的时候,都会有问题,而只有我们使用唯一标识p.id的时候才会正常。
如果我们 想把这个问题讲清楚,就一定要了解两个东西,key的工作原理还有虚拟DOM的对比算法
接下来我们就详细讲解一下其中的细节
当使用index作为key的时候
首先在我们准备好数据之后,Vue会拿着我们的数据生成虚拟DOM,然后再将虚拟DOM转为真实的DOM。表现图如下:
这里要格外的注意,用户是在真实DOM中输入内容的,而虚拟DOM是在内存里得,虚拟DOM是用户无法操作的。用户能操作的都是真实DOM。
接下来我们再看看数据更新的情况:
我们在所有人的前面添加了一个老六,那么Vue就会根据新数据生成虚拟DOM,而此时生成的虚拟DOM中老六的key就变成0了,而张三,李四,王五的key都依次顺延了一位。
那么接下来又会发生什么呢?有的同学这时候就会说,那应该和刚才一样呀,直接把新生成的虚拟DOM转为真实DOM就行了。
那如果是这样的话,Vue所使用的这个虚拟DOM的环境不就啥用也没有了嘛?反而还多了一个中间环节。浪费了很多时间。所以Vue其实并不是这样去做的。
现在摆在Vue面前的有两份虚拟DOM,一份是旧的,一份是新的。那么Vue这个时候就会去做一个事情,那就是虚拟DOM的对比算法。而对比的时候,就会依赖key。那具体是怎么对比的呢?我接下来再细说一下。
首先Vue会看第一个老六-40,它的key为0,然后他就会去旧DOM中找有没有key为0的,找到之后它就会去比较里面的内容,我们可以看到key为0的新DOM中是老六-40,而旧DOM中是张三-18,那么就发现两边的文本出现了不一致。然后再接着对比后面的input,我们可以看到两边的input是一样的。这个时候有的同学就会发出疑问,旧的DOM中如果残留着用户填写的信息的话,两边的虚拟DOM不就不一样了嘛?这里就需要我们注意一下,Vue这里比较的是在内存中的虚拟DOM,而input中填写的内容是在真实DOM中的。所以Vue这里针对input的对比结果就是两边的input是一样的。
说到这里重点就来了,那么针对比对出来的不一致的文本内容还有比较一致的input标签,Vue会做什么处理呢?
针对内容不一致的老六-40,Vue就会重新生成一个新的真实DOM,而针对被判定为一致的input标签,则继续沿用key为0,之前已经生成的真实DOM,就没必要再生成一次了,所以就会有以下情况。
所以以此类推,由于key使用了index,而且新加的节点被置于顶部,就导致所有节点的key都发生了变化,而input还是对应着之前的key,就导致input中有内容的时候,都发生了错位现象。
所以这里也就能解释为什么使用唯一标识p.id作为key的时候不会有这样的问题,因为不管位置怎么变化,Vue在使用比较算法的时候,key都是可以对应上的,而input,也不会发生错位的现象。
那为什么我们不写key的时候也会发生错位的现象呢?这是因为当我们不写key的时候,Vue就会默认使用index作为key,所以也会出现错位现象。
5.总结
面试题:react,Vue中的key有什么作用?(key的内部原理)
1.虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化的时候,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:
如果虚拟DOM中的内容没变,则直接使用之前生成的真是DOM!
如果虚拟DOM中的内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到页面
3.用index作为key可能会引发的问题:
(1)若对数据进行逆序添加,逆序删除等破坏顺序的操作,则会产生没有必要的真实DOM更新,界面效果没问题,但是效率低
(2)如果结构中还包含输入类的DOM,则会产生错误DOM更新,界面会有问题
4.开发中如何选择key?
(1)最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值
(2)如果不存在对数据的逆序添加,逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,则使用index作为key是没有问题的。



