来自《Vue.js快跑》
当使用v-for指令遍历一个数组或是对象,并且给定的数组或对象改变时,Vue不会再重复生成所有的元素,而是智能地找到需要更改的元素,并且只更改这些元素。例如,如果有一个作为列表元素输出到页面上的数组,在它的末尾添加一个新元素,那么页面上现有的元素将保持不变,同时在末尾,新的元素会被创建。如果数组中间的一个元素改变了,则页面上只有对应的元素会更新。可是,如果你在数组的中间删除或是添加一个元素,Vue不会知道该元素对应的是页面上哪一个元素,它会更新从删除或是添加元素的位置到列表结尾之间的每一个元素。对于简单的内容,这也许不是一个问题,但对于复杂的内容和组件,你肯定不希望Vue这么做。使用v-for指令时可以设置一个key属性,通过它可以告诉Vue数组中的每个元素应该与页面上哪个元素相关联,从而删除正确的元素。key属性的值默认为元素在循环时的索引。可以通过下面的代码来了解这是如何工作的:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<demo-key v-for="(item, i) in items" @click.native="items.splice(i, 1)" :key='item'>
{{ item, i }}
</demo-key>
</div>
<script>
const randomColor = () => `hsl(${Math.floor(Math.random() * 360)}, 75%, 85%)`;
const DemoKey = {
template: `<p :style="{ backgroundColor: color }"><slot></slot></p>`,
data: () => ({
color: randomColor()
})
};
new Vue({
el: '#app',
components: {
DemoKey
},
data: () => ({
items: ['one', 'two', 'three', 'four', 'five']
}),
});
</script>
</body>
</html>
上面的示例会输出5个颜色随机的、包含数字1到5的段落元素,如下所示:
单击其中的一个段落元素,会将对应的元素从items数组中删除。如果单击第二个段落元素——即图中标签为two的元素——希望那个元素会被彻底删除,然后标签为three的元素会变成第二个。实际上并不会这样!最终你得到的是下面这样的结果:
这是Vue的差异对比机制引起的:删除了数组中的第二个元素,而原本的位置上将会变成第三个元素,于是Vue更新页面上对应元素的文本来反映变化,对于下个元素、下下个元素都是如此,一直到数组的结尾。最终它会删除最后一个元素。不过,这很可能并不是你想要的,所以为这个示例添加一个key属性,来告诉Vue应该删除哪个元素:
<template>
<demo-key
v-for="(item, i) in items" :key="item"
@click.native="items.splice(i, 1)">
{{ item }}
</demo-key>
</template>
key属性必须是一个唯一的数字或者字符串,并与数组中的元素相对应。这个例子中,数组的元素自身就是字符串,所以可以把它们用作key。
我经常看到有人将key设置为数组的下标(例如在前面例子中设置:key="i")。如果不是什么特殊情况,那么你不会想要这么做的!虽然Vue不会再发出警告,但你会遇到与我刚才向你展示的完全相同的问题,一个并非你期望的元素将被删除。
现在,单击第二个元素将会把two从数组中删除,同时对应的元素也将被删除,结果如下:
总之,无论什么情况,只要允许就应该设置一个key。在组件中使用v-for指令时key属性并不是可选的,正如你在前面的示例中看到的,在那个示例中,Vue将会在控制台中显示一个警告。