Vue列表渲染是Vue中一个重要的功能,它可以帮助我们快速地将数据渲染到页面上。下面是一个简单的Vue列表渲染的代码示例:
<template> <div> <ul> <li v-for="item in items" :key="item.id">{{ item.name }}</li> </ul> </div> </template> <script> export default { data () { return { items: [{ id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }, { id: 3, name: 'Orange' }] } } } </script>
在上面的代码中,我们使用了v-for来遍历items数组,并将其中的name属性值输出到页面上。此外,我们还使用了key属性来标识当前遍历的元素,这样可以有效地优化Vue列表渲染的性能。
Vue列表渲染不仅可以用于遍历数组,还可以用于遍历对象。下面是一个使用v-for遍历对象的例子:
<template> <div> <ul> <#用
v-for
把一个数组对应为一组元素我们可以用
v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用item in items
形式的特殊语法,其中 items 是源数据数组,而item
则是被迭代的数组元素的别名。<ul id="array-rendering"> <li v-for="item in items"> {{ item.message }} </li> </ul>
Vue.createApp({ data() { return { items: [{ message: "Foo" }, { message: "Bar" }] } } }).mount("#array-rendering")
结果: 点击此处实现
在
v-for
块中,我们可以访问所有父作用域的 property。v-for
还支持一个可选的第二个参数,即当前项的索引。<ul id="array-with-index"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul>
Vue.createApp({ data() { return { parentMessage: "Parent", items: [{ message: "Foo" }, { message: "Bar" }] } } }).mount("#array-with-index")
结果: 点击此处实现
你也可以用
of
替代in
作为分隔符,因为它更接近 JavaScript 迭代器的语法:<div v-for="item of items"></div>
#在
v-for
里使用对象你也可以用
v-for
来遍历一个对象的 property。<ul id="v-for-object" class="demo"> <li v-for="value in myObject"> {{ value }} </li> </ul>
Vue.createApp({ data() { return { myObject: { title: "How to do lists in Vue", author: "Jane Doe", publishedAt: "2016-04-10" } } } }).mount("#v-for-object")
结果: 点击此处实现
你也可以提供第二个的参数为 property 名称 (也就是键名 key):
<li v-for="(value, name) in myObject"> {{ name }}: {{ value }} </li>
点击此处实现
还可以用第三个参数作为索引:
<li v-for="(value, name, index) in myObject"> {{ index }}. {{ name }}: {{ value }} </li>
点击此处实现
提示
在遍历对象时,会按
Object.keys()
的结果遍历,但是不能保证它在不同 JavaScript 引擎下的结果都一致。#维护状态
当 Vue 正在更新使用
v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一
key
attribute:<div v-for="item in items" :key="item.id"> <!-- content --> </div>
建议尽可能在使用
v-for
时提供key
attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。因为它是 Vue 识别节点的一个通用机制,
key
并不仅与v-for
特别关联。后面我们将在指南中看到,它还具有其它用途。提示
不要使用对象或数组之类的非基本类型值作为
v-for
的 key。请用字符串或数值类型的值。更多
key
attribute 的细节用法请移步至key
的 API 文档。#数组更新检测
#变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
你可以打开控制台,然后对前面例子的
items
数组尝试调用变更方法。比如example1.items.push({ message: "Baz" })
。#替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如
filter()
、concat()
和slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:example1.items = example1.items.filter(item => item.message.match(/Foo/))
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
#显示过滤/排序后的结果
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
例如:
<li v-for="n in evenNumbers">{{ n }}</li>
data() { return { numbers: [ 1, 2, 3, 4, 5 ] } }, computed: { evenNumbers() { return this.numbers.filter(number => number % 2 === 0) } }
在计算属性不适用的情况下 (例如,在嵌套
v-for
循环中) 你可以使用一个方法:<ul v-for="numbers in sets"> <li v-for="n in even(numbers)">{{ n }}</li> </ul>
data() { return { sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]] } }, methods: { even(numbers) { return numbers.filter(number => number % 2 === 0) } }
#在
v-for
里使用值的范围
v-for
也可以接受整数。在这种情况下,它会把模板重复对应次数。<div id="range" class="demo"> <span v-for="n in 10">{{ n }} </span> </div>
结果: 点击此处实现
#在
<template>
中使用v-for
类似于
v-if
,你也可以利用带有v-for
的<template>
来循环渲染一段包含多个元素的内容。比如:<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider" role="presentation"></li> </template> </ul>
#
v-for
与v-if
一同使用TIP
注意我们不推荐在同一元素上使用
v-if
和v-for
。更多细节可查阅风格指南。当它们处于同一节点,
v-if
的优先级比v-for
更高,这意味着v-if
将没有权限访问v-for
里的变量:<!-- This will throw an error because property "todo" is not defined on instance. --> <li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo }} </li>
可以把
v-for
移动到<template>
标签中来修正:<template v-for="todo in todos"> <li v-if="!todo.isComplete"> {{ todo }} </li> </template>
#在组件上使用
v-for
这部分内容假定你已经了解组件相关知识。你也完全可以先跳过它,以后再回来查看。
在自定义组件上,你可以像在任何普通元素上一样使用
v-for
:<my-component v-for="item in items" :key="item.id"></my-component>
然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要使用 props:
<my-component v-for="(item, index) in items" :item="item" :index="index" :key="item.id" ></my-component>
不自动将
item
注入到组件里的原因是,这会使得组件与v-for
的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。下面是一个简单的 todo 列表的完整例子:
<div id="todo-list-example"> <form v-on:submit.prevent="addNewTodo"> <label for="new-todo">Add a todo</label> <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat" /> <button>Add</button> </form> <ul> <todo-item v-for="(todo, index) in todos" :key="todo.id" :title="todo.title" @remove="todos.splice(index, 1)" ></todo-item> </ul> </div>
const app = Vue.createApp({ data() { return { newTodoText: "", todos: [ { id: 1, title: "Do the dishes" }, { id: 2, title: "Take out the trash" }, { id: 3, title: "Mow the lawn" } ], nextTodoId: 4 } }, methods: { addNewTodo() { this.todos.push({ id: this.nextTodoId++, title: this.newTodoText }) this.newTodoText = "" } } }) app.component("todo-item", { template: ` <li> {{ title }} <button @click="$emit("remove")">Remove</button> </li> `, props: ["title"] }) app.mount("#todo-list-example")
点击此处实现
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。#组件名在注册一个组件的时候,我们始终需要给它...
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。#事件名不同于组件和 prop,事件名不存在任何自动...
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。通常,当我们需要将数据从父组件传递到子组件时,...
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。尽管存在 prop 和事件,但有时你可能仍然需要直接...