在Vue中v-for通常会制定一个key属性,但是这个key属性有时候用索引值index,也有时候用id值。其实用id、手机号、身份证号等唯一值作为key更为合适,下面通过代码说明一下key值的选择。
<template>
<div id="app">
<ul>
<!-- 循环列表 使用index值作为key值 -->
<li v-for="(p, index) of persons" :key="index">
{{p.name}}-->{{p.age}}
<input type="text" v-model="p.name">
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
persons:[
{id:'001',name:'马冬梅',age:30,gender:'女'},
{id:'002',name:'周冬雨',age:31,gender:'女'},
{id:'003',name:'周杰伦',age:18,gender:'男'},
{id:'004',name:'温兆伦',age:19,gender:'男'}
]
}
}
}
</script>
<!-- 循环列表 使用id作为key值 -->
<li v-for="p of persons" :key="p.id">
单纯遍历数组无论是使用id还是index作为key,页面最终显示的结果都是一样的,在这里我们看不出有什么区别。
对数组进行逆序添加、逆序删除等破坏性操作时(以逆序添加为例)
先使用id作为可以key值
<!-- html代码 -->
<div id="app">
<h2>人员列表</h2>
<button @click="add">添加一个宋铁</button>
<ul>
<!-- 循环列表 使用id作为key值 -->
<li v-for="p of persons" :key="p.id">
{{p.name}}-->{{p.age}}
<input type="text">
</li>
</ul>
</div>
<!-- js代码 -->
methods:{
add() {
const tieSong = {id:'005', name:'宋轶', age:18, gender:'女'}
//往数组第一位追加一个元素
this.persons.unshift(tieSong)
}
}
当使用id作为可以值时,显示的结果是正常的
使用index作为key值
<li v-for="(p, index) of persons" :key="index">
{{p.name}}-->{{p.age}}
<input type="text">
</li>
点击按钮逆序添加时,结果如下:
用index作为key值逆序添加的时候,页面发生了错误DOM更新,这是因为Vue中的虚拟DOM对比diff算法,比较规则如下:
当在旧的虚拟DOM中找到与新的虚拟DOM相同的key时:
(1)若虚拟DOM中内容没有发生变化,则直接复用之前真实DOM
(2)若虚拟DOM中内容发生变化时,则生成新的真实DOM替换原来的真实DOM
当在旧的虚拟DOM未找到与新的虚拟DOM相同的key时:
创建真实DOM,重新渲染到页面上
总结:key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新旧虚拟DOM的差异比较,当key相同,新旧虚拟DOM内容也相同时,则对应的真实DOM复用,不同时则重新生成真实DOM。开发中推荐使用唯一标识作为key值,即使是仅用于渲染列表时,在更新的时候也能更加高效,因为可以直接复用真实DOM。本文仅代表个人见解,如有错误,还请各位批评指证。