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 简写

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


“关键”属性

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

元素被错误重用的原因是元素没有唯一标识符,而这正是我们使用的key属性 for:让 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

运行示例 »

如前所述:当删除元素时最喜欢的图片从“鱼”变成“蛋糕”的错误与 Vue 通过重用元素来优化页面有关,同时 Vue 无法完全区分元素。这就是为什么我们应该始终包括key生成元素时唯一标记每个元素的属性v-for。当我们使用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"
/>
运行示例 »

Vue练习

通过练习测试一下

练习:

当使用 v-for 生成元素时,始终建议使用哪个特定属性?

<fish-type
  v-for="x in fish"
  :="x.id"
  :fish-name="x.name"
  :img-url="x.url"
/>

开始练习