Vue v-for 组件

组件可以与 v-for 一起重用,以生成许多相同类型的元素。

当从组件中使用 v-for 生成元素时,可以根据数组中的值动态赋值 Props 也非常有用。


使用 v-for 创建组件元素

现在,我们将基于一个带有食物项目名称的数组,使用 v-for 创建组件元素。

实例

App.vue:

  1. <template>
  2. <h1>Food</h1>
  3. <p>Components created with v-for based on an array.</p>
  4. <div id="wrapper">
  5. <food-item
  6. v-for="x in foods"
  7. v-bind:food-name="x"></food>
  8. </div>
  9. </template>
  10. <script>
  11. export default {
  12. data() {
  13. return {
  14. foods: ['Apples','Pizza','Rice','Fish','Cake']
  15. };
  16. }
  17. }
  18. </script>

FoodItem.vue:

  1. <template>
  2. <div>
  3. <h2>{{ foodName }}</h2>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. props: ['foodName']
  9. }
  10. </script>

v-bind 简写

为了动态绑定 props,我们使用了 v-bind,因为我们现在将比以前更多地使用 v-bind,因此我们将在本教程的其余部分中使用 v-bind: 简写 :


'key' 属性

如果我们在使用 v-for 创建元素后修改数组,则可能会出现错误,因为 Vue 更新使用 v-for 生成的元素的方式。Vue 重用元素来优化性能,因此,如果我们删除一个项,就会重用现有的元素,而不是重新创建所有元素,并且元素属性可能不再正确。

元素被错误地重用的原因是元素没有唯一的标识符,这正是我们使用 key 属性的目的:让 Vue 区分元素。我们将在没有 key 属性的情况下生成错误行为,但首先让我们使用 v-for 构建一个包含食物的网页来显示:食物名称、描述、喜爱食物的图像和更改喜爱状态的按钮。

实例

App.vue:

  1. <template>
  2. <h1>Food</h1>
  3. <p>Food items are generated with v-for from the 'foods' array.</p>
  4. <div id="wrapper">
  5. <food-item
  6. v-for="x in foods"
  7. :food-name="x.name"
  8. :food-desc="x.desc"
  9. :is-favorite="x.favorite"></food>
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. data() {
  15. return {
  16. foods: [
  17. { name: 'Apples',
  18. desc: 'Apples are a type of fruit that grow on trees.',
  19. favorite: true },
  20. { name: 'Pizza',
  21. desc: 'Pizza has a bread base with tomato sauce, cheese, and toppings on top.',
  22. favorite: false },
  23. { name: 'Rice',
  24. desc: 'Rice is a type of grain that people like to eat.',
  25. favorite: false }
  26. { name: 'Fish',
  27. desc: 'Fish is an animal that lives in water.',
  28. favorite: true }
  29. { name: 'Cake',
  30. desc: 'Cake is something sweet that tastes good.',
  31. favorite: false }
  32. ]
  33. };
  34. }
  35. }
  36. </script>
  37. <style>
  38. #wrapper {
  39. display: flex;
  40. flex-wrap: wrap;
  41. }
  42. #wrapper > div {
  43. border: dashed black 1px;
  44. flex-basis: 120px;
  45. margin: 10px;
  46. padding: 10px;
  47. background-color: lightgreen;
  48. }
  49. </style>

FoodItem.vue:

  1. <template>
  2. <div>
  3. <h2>
  4. {{ foodName }}
  5. <img src="/img_quality.svg" v-show="foodIsFavorite">
  6. </h2>
  7. <p>{{ foodDesc }}</p>
  8. <button v-on:click="toggleFavorite">Favorite</button>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. props: ['foodName','foodDesc','isFavorite'],
  14. data() {
  15. return {
  16. foodIsFavorite: this.isFavorite
  17. }
  18. },
  19. methods: {
  20. toggleFavorite() {
  21. this.foodIsFavorite = !this.foodIsFavorite;
  22. }
  23. }
  24. }
  25. </script>
  26. <style>
  27. img {
  28. height: 1.5em;
  29. float: right;
  30. }
  31. </style>

为了了解我们需要 key 属性,让我们创建一个按钮来删除数组中的第二个元素。当这种情况发生时,如果没有 key 属性,最喜欢的图像将从 'Fish' 元素转移到 'Cake' 元素,这是不正确的:

实例

与上一个实例的唯一区别是我们添加了一个按钮:

  1. <button @click="removeItem">Remove Item</button>

还有一个在 App.vue 方法:

  1. methods: {
  2. removeItem() {
  3. this.foods.splice(1,1);
  4. }
  5. }

如前所述:这个错误是,当元素被删除时,最喜欢的图像从 'fish' 到 'cake',这与 Vue 通过重用元素来优化页面有关,同时 Vue 无法完全区分元素。这就是为什么在使用 v-for 生成元素时,我们应该始终包含 key 属性以唯一地标记每个元素。当我们使用 key 属性时,我们不再遇到这个问题。

我们不使用数组元素索引作为 key 属性值,因为当删除和添加数组元素时,索引会发生变化。我们可以创建一个新的数据属性,为每种食物保留一个唯一的值,比如 ID 号,但由于食物已经有了唯一的名称,我们只能使用它:

实例

我们只需要在 App.vue 中添加一行,就可以唯一地识别使用 v-for 创建的每个元素,并解决问题:

  1. <food-item
  2. v-for="x in foods"
  3. :key="x.name"
  4. :food-name="x.name"
  5. :food-desc="x.desc"
  6. :is-favorite="x.favorite"
  7. />