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"
/>
執行示例 »