数据准备
- 引入Vue.js
- 准备DOM容器
- 使数据和 DOM 容器建立了关联
初始页面如下:
目标
- 在使用v-for渲染页面时,key的作用是什么
- key存在时怎么处理,不存在又怎么处理
- 使用key时,key的值使用什么比较好,是遍历时的index还是数据的id(唯一标识)
测试
body中代码如下:
<body>
<div id="root">
<h2>人员列表</h2>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}}--{{p.age}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
persons: [{
id: 001,
name: '张三',
age: 20
},
{
id: 002,
name: '李四',
age: 22
},
{
id: 003,
name: '王五',
age: 25
}
]
}
})
</script>
</body>
网页如下: 可以观察到,在浏览器元素中的 li 并没有了key属性,去哪里了? ( key属性是Vue内部使用的,模板中的确写了,Vue也使用了,但是key会在Vue的虚拟DOM转为真实DOM时Vue就会把key去除,所以在页面中看不到key)
再看,在Vue.js的官方API中的v-for循环中也是存在key的,
<ul>
<li v-for="item in items" :key="item.id">...</li>
</ul>
经过测试,在书写上述网页页面时index存在,可以正常输出页面,index不存在时,控制台不会报错,页面也是正常输出的, 那它的作用到底是什么呢???
问题发现
需求:添加一个按钮再向 persons[] 数组中添加一条数据:{id:‘004’,name:‘老六’,age:33},并且把该条数据插入到数组的开头。(只有这样才会出先问题,具有说服力)使用 persons.unshift 插入数据。
数据插入完成,数据插入正常、现实正常,控制台没有报错、没有警告,表面上没有存在任何的问题,但是存在以下问题:
1、特殊情况下会发生数据错误 2、效率问题
问题呈现
一、(特殊情况下会发生数据错误) 首先,在每一行数据之后再加上一个input输入框,如下: 再者,向输入框中放入数据,如下: 这时,我们再添加一条新的数据:(问题出现)
数据发生错位,这是我们想要是key不存在呢?会怎么样?如下: 出现同样的问题,那使用p.id (每条数据的唯一标识)呢?如下: 综上所述:关于key在这种特殊的情况下 key为index 出现问题,key不存在也出现问题,只有key为p.id(每条数据的唯一标识)时才没有问题。想要把这个问题说清楚我们就必须对key的工作原理和虚拟DOM的对比算法了解。
Vue的工作原理:
首先Vue会根据我们的初始数据,生成虚拟DOM,虚拟DOM展示为真实DOM完成数据的展示。这时我们修改数据,得到新数据,Vue同样会根据新数据生成虚拟DOM,这个时候并不会根据虚拟DOM就生成新的真实DOM,而是与之前旧的虚拟DOM进行对比,在两份虚拟DOM进行对比时,就会依赖于key。
对比规则: 1、旧虚拟DOM中找到与新DOM相同的key:
- a,若虚拟DOM中的内容没有变,直接使用之前的DOM(复用)。
- b,若虚拟DOM中的内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOM。
2、旧虚拟DOM中未找到与新虚拟DOM相同的key,创建新的真实DOM,在渲染到页面
所以有两情况生成新的DOM:
- 有相同的key,但内容不同
- 没有相同的key
总结
key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
用index作为key可能会引发的问题:
- 若对数据进行:逆序添加,逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没有问题,但效率低
- 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题
在开发中如何选择key?
- 最好使用每条数据的唯一标识作为key,例如:id ,手机号,身份找号,学号等唯一值
- 如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有任何问题的。
|