使用 v-for 时,如果每次迭代的元素是一个对象,而不是一个简单的值,那么建议将数据模型中具有唯一性的属性绑定到 DOM 元素的 key 属性上。
具体的原理:
当 Vuejs 更新使用 v-for 渲染的列表时,默认使用“就地更新”的策略。如果数据项的顺序发生了改变,Vue.js 不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位詈得到正确渲染。假设一个列表对应的数据模型在数组的末尾增加了一个新元素,Vue.is 的做法就是把这个元素放到数组的最后,这自然是最方便的做法。但是,如果数据模型在数组的开头插入了一个元素,那么默认情况下,Vue.is 依然会在数组的最后添加一个元素,然后从第一个元素开始逐个更新,以保持与数据模型的一致。
但是,这种做法在某些情况下就会产生一些问题。下面通过一个例子来进行说明,假设我们想要开发一个微型的“待办事项”(Todo List)页面。我们将在这个页面上列出一些待办事项,用户既可以添加新的待办事项,也可以在某个待办事项的前面打勾,表示已经完成该事项。
<body>
<div id="app">
<div>
<input type="text" v-model="todo">
<button v-on:click="onClick">添加 </button>
</div>
<ul>
<li v-for="item in list"><input type="checkbox">{{item.todo}}</li>
</ul>
</div>
<script>
var vm = new vue({
el:'#app',
data:{
todo:'',
newId:5,
list: [
{id:1,todo:'去上课'},
{id:2,todo:'去购物'},
{id:3,todo:'去看电影'},
{id:4,todo:'去打球'}
]
},
methods:{
onClick(){
// unshift()会在数组的开头插入元素
this.list.unshift({ id: this.newId++, todo: this.todo });
this.todo ='';
}
}
})
</script>
</body>
项目列表都是“就地更新”的,复选框仍然保持着原来的状态,而解决这个问题的方法 就是对li元素绑定key属性--在v-for后面添加v-bind:key:
<li v-for:"item in list" v-bond:key="item.id">
<input type = "checkbox"> {{item.todo}}
</li>
这就是对迭代的元素绑定 key属性的作用所在,可以简单理解为,将 key 属性绑定到数据模型中具有唯一性的属性之后,整个迭代素和数据模型就一一对应了,新元素会按顺序插人原来的列表中,而不是“就地更新”