渲染 Vue 组件列表
现在我们已经有了一个可以工作的组件。接下来我们将添加更多的 ToDoItem
组件到我们的应用中。本文我们会添加一系列待办事项到 App.vue
组件并使用 v-for
指令遍历它们,将它们的每一项展示在 ToDoItem
组件中。
预备条件: |
熟悉核心 HTML、CSS 和 JavaScript 语言,了解终端/命令行知识。 Vue 组件是由管理应用程序数据的 JavaScript 对象和映射到基础 DOM 结构的基于 HTML 的模板语法组成的。为了进行安装并使用 Vue 的一些更高级的功能(例如“单文件组件(SFC)”或渲染功能),你将需要一个装有 node + npm 的终端。 |
---|---|
目标: | 了解如何循环浏览一个数据数组,并在多个组件中渲染。 |
利用 v-for 指令渲染列表
一个有效的待办事项列表需要有多个被渲染的 to-do 项,Vue 中的 v-for
可以用来实现这种效果。它是 Vue 自带的指令,用于在 template 中实现循环,我们可以利用它将数组中的各项重复渲染成指定的特征。我们将利用它迭代待办事项列表,将其中的每一项展示为单独的 ToDoItem
组件。
添加一些需要渲染的数据
首先我们需要准备一个待办事项数组。添加 data
属性到 App.vue
组件对象中,它包含一个 ToDoItems
字段,其值是待办事项数组。在最终完成添加新的待办事项功能之前,我们可以先 mock 一些待办项目,每个待办项目可以用一个对象表示,这个对象含有 label
和 done
属性。
像下面这样添加一些待办项目让我们可以利用 v-for
来对它们进行渲染。
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
获取每个迭代的元素,并渲染它和它的子元素。在我们的例子中,我们用 <li>
的形式展示每一个待办事项,接下来我们会通过每个待办事项传递数据到其对应的 ToDoItem
组件。
Key 属性
在进行数据传递之前,我们要了解下 key
属性,它和 v-for
一起使用,用来帮助 Vue 标识列表中的元素,这样 Vue 就不需要在列表变化时重新创建它们。为了确保它适当地重新使用列表元素,它需要在你附加 v-for
的同一个元素上有一个独特的“key”。
为了确保 Vue 能够准确地比较 key
属性,它们需要是字符串或数字值。虽然使用名字字段很好,但这个字段最终将由用户输入控制,这意味着我们不能保证名字是唯一的。然而,我们可以使用 lodash.uniqueid()
,就像我们在上一篇文章中做的那样。
- 使用导入
ToDoItem
组件相同的方法导入lodash.uniqueid
到App
组件。jsimport uniqueId from "lodash.uniqueid";
-
添加
id
字段到ToDoItems
数组的每一个元素中,并且将他们赋值为uniqueId('todo-')
。 此时,App.vue
中的<script>
元素内容应该如下:jsimport ToDoItem from "./components/ToDoItem.vue"; import uniqueId from "lodash.uniqueid"; export default { name: "app", components: { ToDoItem, }, data() { return { ToDoItems: [ { id: uniqueId("todo-"), label: "Learn Vue", done: false }, { id: uniqueId("todo-"), label: "Create a Vue project with the CLI", done: true, }, { id: uniqueId("todo-"), label: "Have fun", done: true }, { id: uniqueId("todo-"), label: "Create a to-do list", done: false }, ], }; }, };
- 在你的
App.vue
模板中添加v-for
指令和key
属性到<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
了,这意味着我们可以使用v-bind
来传递item
对象的字段给ToDoItem
组件了。这非常有用,我们想让列表中的待办事项的label
值展示到它的 label 中,而不是显示一个静态的“My Todo Item”。此外,我们想让它们的 checked 状态反映它们的done
字段,而不是总设置为done="true"
。 - 把
label="My ToDo Item"
改成:label="item.label"
,:done="false"
改成: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>
现在当你去看运行着的 app 时,你会发现待办事项显示了它们自己正确的名字,如果你查看源码的话,你会发现输入都有了唯一的 id
,它取自 App
组件中的对象。
让我们来一点小重构
在这里我们可以做一个小小的重构。我们可以把 id
变成一个 prop,而不是在 ToDoItem
组件中为复选框生成它。虽然这不是严格意义上的需要,但它使我们更容易管理,因为我们已经需要为每个 todo 项目创建一个唯一的 id
。
- 添加一个新的 prop
id
到ToDoItem
组件。 - 标记它为 required,类型是
String
。 - 为防止命名冲突,删除掉
data
属性中的id
字段。 - 现在不需要再使用
uniqueId
了,所以需要删除掉import uniqueId from 'lodash.uniqueid';
这行,否则你的应用会报错。
现在,ToDoItem
中的 <script>
内容应该如下所示:
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
template 应该如下所示:
<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>
你渲染后的站点看起来是没有变化的,但是这次重构使得 item.id
像其他参数一样,作为 prop 从 App.vue
传递给 ToDoItem
。现在代码变得更有逻辑性和一致性。