Vue v-for 组件
组件可以使用 v-for
重用,以生成相同类型的许多元素。
当使用 v-for
从组件生成元素时,props 可以基于数组中的值动态分配,这也是非常有用的。
使用 v-for 创建组件元素
现在,我们将基于包含食物名称的数组,使用 v-for
来创建组件元素。
示例
App.vue
:
<template>
<h1>Food</h1>
<p>Components created with v-for based on an array.</p>
<div id="wrapper">
<food-item
v-for="x in foods"
v-bind:food-name="x"/>
</div>
</template>
<script>
export default {
data() {
return {
foods: ['Apples','Pizza','Rice','Fish','Cake']
};
}
}
</script>
FoodItem.vue
:
<template>
<div>
<h2>{{ foodName }}</h2>
</div>
</template>
<script>
export default {
props: ['foodName']
}
</script>
运行示例 »
v-bind 简写
为了动态绑定 props,我们使用 v-bind
,并且由于现在我们将比以前更多地使用 v-bind
,因此在本教程的其余部分中我们将使用 v-bind:
的简写 :
。
‘key’ 属性
如果我们修改了数组,在元素已经用 v-for
创建之后,可能会出现错误,这是因为 Vue 更新通过 v-for
创建的元素的方式。Vue 为了优化性能会重用元素,所以如果我们删除了一个项,就会重用已存在的元素而不是重新创建所有元素,这可能导致元素属性不再正确。
导致元素被错误重用的原因是元素没有唯一标识符,而这正是我们使用 key
属性的目的:让 Vue 能够区分元素。
我们将展示没有 key
属性时的错误行为,但首先让我们创建一个包含食物的网页,使用 v-for
来显示:食物名称、描述、最喜欢的食物的图片以及更改最喜欢状态的按钮。
示例
App.vue
:
<template>
<h1>Food</h1>
<p>Food items are generated with v-for from the 'foods' array.</p>
<div id="wrapper">
<food-item
v-for="x in foods"
:food-name="x.name"
:food-desc="x.desc"
:is-favorite="x.favorite"/>
</div>
</template>
<script>
export default {
data() {
return {
foods: [
{ name: 'Apples',
desc: 'Apples are a type of fruit that grow on trees.',
favorite: true },
{ name: 'Pizza',
desc: 'Pizza has a bread base with tomato sauce, cheese, and toppings on top.',
favorite: false },
{ name: 'Rice',
desc: 'Rice is a type of grain that people like to eat.',
favorite: false }
{ name: 'Fish',
desc: 'Fish is an animal that lives in water.',
favorite: true }
{ name: 'Cake',
desc: 'Cake is something sweet that tastes good.',
favorite: false }
]
};
}
}
</script>
<style>
#wrapper {
display: flex;
flex-wrap: wrap;
}
#wrapper > div {
border: dashed black 1px;
flex-basis: 120px;
margin: 10px;
padding: 10px;
background-color: lightgreen;
}
</style>
FoodItem.vue
:
<template>
<div>
<h2>
{{ foodName }}
<img src="/img_quality.svg" v-show="foodIsFavorite">
</h2>
<p>{{ foodDesc }}</p>
<button v-on:click="toggleFavorite">Favorite</button>
</div>
</template>
<script>
export default {
props: ['foodName','foodDesc','isFavorite'],
data() {
return {
foodIsFavorite: this.isFavorite
}
},
methods: {
toggleFavorite() {
this.foodIsFavorite = !this.foodIsFavorite;
}
}
}
</script>
<style>
img {
height: 1.5em;
float: right;
}
</style>
运行示例 »
为了看到 key
属性的必要性,让我们创建一个按钮来移除数组中的第二个元素。当发生这种情况时,没有 key
属性,收藏图片会从 'Fish' 元素转移到 'Cake' 元素,这显然是不正确的。
示例
与之前的示例唯一的区别是,我们添加了一个按钮
<button @click="removeItem">Remove Item</button>
以及一个方法
methods: {
removeItem() {
this.foods.splice(1,1);
}
}
在 App.vue
中。
如前所述:这种错误,即当移除一个元素时,收藏图片会从 'fish' 变为 'cake',这与 Vue 通过重用元素来优化页面有关,同时 Vue 无法完全区分这些元素。这就是为什么我们在使用 v-for
生成元素时,应该始终包含 key
属性来唯一标识每个元素。当我们使用 key
属性时,这个问题就不再存在了。
我们不使用数组元素索引作为 key
属性的值,因为当数组元素被移除和添加时,它会发生变化。我们可以创建一个新的数据属性来为每个项保留一个唯一值,比如 ID 号,但由于食物项已经有唯一的名称,我们也可以直接使用名称。
示例
我们只需要在 App.vue
中添加一行代码,就可以唯一标识由 v-for
创建的每个元素并修复问题。
<food-item
v-for="x in foods"
:key="x.name"
:food-name="x.name"
:food-desc="x.desc"
:is-favorite="x.favorite"
/>
运行示例 »