渲染 Vue 组件列表

在这一点上,我们已经拥有了一个完全工作的组件;现在我们准备将多个ToDoItem组件添加到我们的应用程序中。在本文中,我们将了解如何将一组待办事项数据添加到我们的App.vue组件中,然后我们将循环遍历这些数据并在ToDoItem组件内使用v-for指令显示它们。

先决条件

熟悉核心HTMLCSSJavaScript语言,了解终端/命令行

Vue 组件被编写为 JavaScript 对象(管理应用程序数据)和基于 HTML 的模板语法(映射到底层 DOM 结构)的组合。对于安装,以及使用 Vue 的一些更高级的功能(如单文件组件或渲染函数),您需要一个安装了 node + npm 的终端。

目标 学习如何循环遍历数据数组并在多个组件中渲染它。

使用 v-for 渲染列表

为了成为一个有效的待办事项列表,我们需要能够渲染多个待办事项。为此,Vue 有一个特殊的指令,v-for。这是一个内置的 Vue 指令,它允许我们在模板内包含一个循环,为数组中的每个项目重复渲染模板功能。我们将使用它来迭代待办事项数组并在我们的应用程序中以单独的ToDoItem组件显示它们。

添加一些要渲染的数据

首先,我们需要获取一个待办事项数组。为此,我们将向App.vue组件对象添加一个data属性,其中包含一个ToDoItems字段,其值为待办事项数组。虽然我们最终会添加一个添加新待办事项的机制,但我们可以先从一些模拟待办事项开始。每个待办事项都将由一个包含labeldone属性的对象表示。

添加一些示例待办事项,类似于下面显示的那些。这样,您就可以使用v-for渲染一些可用数据。

js
export default {
  name: "app",
  components: {
    ToDoItem,
  },
  data() {
    return {
      ToDoItems: [
        { label: "Learn Vue", done: false },
        { label: "Create a Vue project with the CLI", done: true },
        { label: "Have fun", done: true },
        { label: "Create a to-do list", done: false },
      ],
    };
  },
};

现在我们有了项目列表,我们可以使用v-for指令来显示它们。指令应用于像其他属性一样的元素。在v-for的情况下,您使用类似于 JavaScript 中for...in循环的特殊语法——v-for="item in items"——其中items是要迭代的数组,item是对数组中当前元素的引用。

v-for附加到您要重复的元素,并渲染该元素及其子元素。在本例中,我们希望为ToDoItems数组中的每个待办事项显示一个<li>元素。然后,我们希望将每个待办事项的数据传递给ToDoItem组件。

键属性

在这样做之前,还有一个关于与v-for一起使用的语法需要了解,即key属性。为了帮助 Vue 优化渲染列表中的元素,它尝试修补列表元素,以便它不会在每次列表更改时都重新创建它们。但是,Vue 需要帮助。为了确保它正确地重用列表元素,它需要在您附加v-for的相同元素上有一个唯一的“键”。

为了确保 Vue 可以准确地比较key属性,它们需要是字符串或数字值。虽然使用名称字段会很好,但此字段最终将由用户输入控制,这意味着我们无法保证名称是唯一的。但是,我们可以像在上一篇文章中一样使用nanoid()

  1. 使用以下方法将nanoid导入到您的App组件中,就像您使用ToDoItem组件一样:
    js
    import { nanoid } from "nanoid";
    
  2. 接下来,在您的ToDoItems数组中的每个元素中添加一个id字段,并为每个元素分配一个"todo-" + nanoid()的值。App.vue中的<script>元素现在应该包含以下内容:
    js
    import ToDoItem from "./components/ToDoItem.vue";
    import { nanoid } from "nanoid";
    
    export default {
      name: "app",
      components: {
        ToDoItem,
      },
      data() {
        return {
          ToDoItems: [
            { id: "todo-" + nanoid(), label: "Learn Vue", done: false },
            {
              id: "todo-" + nanoid(),
              label: "Create a Vue project with the CLI",
              done: true,
            },
            { id: "todo-" + nanoid(), label: "Have fun", done: true },
            {
              id: "todo-" + nanoid(),
              label: "Create a to-do list",
              done: false,
            },
          ],
        };
      },
    };
    
  3. 现在,将v-for指令和key属性添加到App.vue模板中的<li>元素中,如下所示:
    html
    <ul>
      <li v-for="item in ToDoItems" :key="item.id">
        <to-do-item label="My ToDo Item" :done="true"></to-do-item>
      </li>
    </ul>
    
    当您进行此更改时,<li>标签之间的每个 JavaScript 表达式除了其他组件属性外,还可以访问item值。这意味着我们可以将项目对象的字段传递给我们的ToDoItem组件——只需记住使用v-bind语法即可。这非常有用,因为我们希望我们的待办事项显示其label属性作为其标签,而不是“我的待办事项”的静态标签。此外,我们希望它们的选中状态反映其done属性,而不是始终设置为done="true"
  4. label="My ToDo Item"属性更新为:label="item.label",并将:done="true"属性更新为:done="item.done",如下面的上下文中所示:
    html
    <ul>
      <li v-for="item in ToDoItems" :key="item.id">
        <to-do-item :label="item.label" :done="item.done"></to-do-item>
      </li>
    </ul>
    

现在,当您查看正在运行的应用程序时,它将显示待办事项及其正确的名称,如果您检查源代码,您会看到所有输入都具有唯一的id,这些id取自App组件中的对象。

The app with a list of todo items rendered.

轻微重构的机会

这里我们可以进行一点重构。与其在ToDoItem组件内生成复选框的id,我们可以将id转换为一个 prop。虽然这不是严格必要的,但它使我们更容易管理,因为无论如何我们都需要为每个待办事项创建一个唯一的id

  1. 向您的ToDoItem组件添加一个新的 prop——id
  2. 使其成为必需的,并将其类型设置为String
  3. 为了防止名称冲突,请从您的data属性中删除id字段。
  4. 您不再使用nanoid,因此您需要删除import { nanoid } from 'nanoid';行,否则您的应用程序将抛出错误。

ToDoItem组件中的<script>内容现在应该如下所示:

js
export default {
  props: {
    label: { required: true, type: String },
    done: { default: false, type: Boolean },
    id: { required: true, type: String },
  },
  data() {
    return {
      isDone: this.done,
    };
  },
};

现在,在您的App.vue组件中,将item.id作为 prop 传递给ToDoItem组件。您的App.vue模板现在应该如下所示:

html
<template>
  <div id="app">
    <h1>My To-Do List</h1>
    <ul>
      <li v-for="item in ToDoItems" :key="item.id">
        <to-do-item
          :label="item.label"
          :done="item.done"
          :id="item.id"></to-do-item>
      </li>
    </ul>
  </div>
</template>

当您查看渲染的站点时,它应该看起来相同,但是我们的重构现在意味着我们的id是从App.vue内部的数据中获取并作为 prop 传递到ToDoItem中,就像其他所有内容一样,因此现在事情变得更加逻辑和一致。

总结

这让我们来到了另一篇文章的结尾。我们现在已经有了示例数据,以及一个循环,该循环获取每个数据片段并在应用程序中的ToDoItem内渲染它。

我们接下来真正需要的是允许用户将自己的待办事项输入应用程序的功能,为此,我们需要一个文本<input>、一个在数据提交时触发的事件、一个在提交时触发的添加数据并重新渲染列表的方法,以及一个控制数据的模型。我们将在下一篇文章中介绍这些内容。