Vue 3.0学习笔记之 列表渲染
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
#用 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')