key的原理与作用
我们在写v-for的时候,都需要添加:key属性,并且将数据中的唯一标识作为:key的值
那么为什么要添加:key属性呢?通常的解释是,vue效率会下降,而且会引发意料之外的错误
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0"> <title>Title</title> </head> <body> <script src="../js/vue.js"></script> <div id="app"> <div> <button @click="pushChen">add</button> <div v-for="(item,index) in message" :key="index"> {{item.name}}+{{item.age}} <input type="text"> </div> </div> </div> <script> const app = new Vue({ el: '#app', data: { message: [ { id: 1, name:'周周', age:'21' }, { id: 2, name:'老赵', age:'20' }, { id: 3, name:'爱酱', age:'22' } ] }, methods:{ pushChen(){ //向数组头部添加一个元素 this.message.unshift({id:4,name:'老陈',age:19}) } } }) </script> </body> </html>
这个例子中我们将index作为key的值,我们先在各自的输入框内输入各自的名字,作为记号,后点击添加按钮,向数组头部添加我们一个元素老陈,我们想要的效果是在头部添加老陈之后,老陈后面的输入框应该是空白的,但是,我们却看到,周周的输入框跑到了老陈的后面
原因是什么呢?
vue的工作原理是在生成真实dom之前会先生成虚拟dom,下图用于演示虚拟dom对比算法,所谓对比,就是看长的一不一样,不一样就更新,一样就复用
在其中的第二步,vue的虚拟dom对比第一个li的时候,新的虚拟dom中的key=0的值(老刘)和原来的虚拟dom中的key=0的值(张三)对应不上(两个dom长的不一样),那么此时,就会选择更新真实dom,第一个li被放到了真实dom中,老刘生成了,但是对比老刘li和张三li中的input,vue发现,这俩玩意长得一样(其实原先的input中我们输入了张三),那么它就不做更新,直接放到老刘li的后面,之后以此类推,最终变成了错位
我们看出,这个例子中,由于我们使用了index作为key的值,导致最终的错误,并且导致效率低下(老刘张三李四王五都被更新了),那么,我们如果按照要求,key的值使用数据中的唯一标识,就不会出现这个问题
最后一点,如果不写key,也会导致这个问题,不写key,vue会默认将index作为key的值,结果和最开始的情况如出一辙
所以,什么时候会出现问题呢?对数据进行破坏顺序的操作的时候,会产生多次dom更新,引发效率问题,如果结构中还包含输入类的dom的时候,会产生错误的dom更新,界面出现问题
总而言之,不管什么时候都得加上key,并且将唯一标识设置为key的值