列表渲染
本教程共 40 篇 · 第 9 篇 · 更新于 2026-07-29 · 约 7 分钟阅读
9. 列表渲染
本节目标:学会用 v-for 渲染列表,理解 key 的作用,掌握数组变更检测和过滤排序。
v-for 基础
v-for 根据数组渲染列表,语法是 item in items:
<li v-for="item in items">
{{ item.message }}
</li>
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
items 是数据源,item 是迭代时的别名。
v-for 作用域里可以访问父作用域的所有属性。还支持第二个别名表示索引:
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
作用域规则类似 JavaScript 的 forEach:
items.forEach((item, index) => {
// 能访问外部的 parentMessage
// item 和 index 只在回调里可用
})
也能用解构:
<li v-for="{ message } in items">
{{ message }}
</li>
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
嵌套 v-for 也能访问父作用域:
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
Tip分隔符也可以用
of,更像 JavaScript 迭代器语法:v-for="item of items"。
遍历对象
v-for 也能遍历对象的属性,顺序基于 Object.keys():
<li v-for="value in myObject">
{{ value }}
</li>
第二个参数是键名:
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
第三个参数是索引:
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
范围 v-for
v-for 可以接收整数,从 1 到 n 重复模板:
<span v-for="n in 10">{{ n }}</span>
注意 n 从 1 开始,不是 0。
template 包装
和 v-if 一样,用 <template> 包装多个元素:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider"></li>
</template>
</ul>
key 的作用
Vue 更新 v-for 渲染的列表时,默认用”就地更新”策略。数据顺序变了,Vue 不会移动 DOM,而是就地更新每个元素。
这个默认策略高效,但只适用于不依赖子组件状态或临时 DOM 状态的场景。
要帮 Vue 追踪每个节点的身份,需要给每项加唯一的 key:
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
<template v-for> 的 key 放在 <template> 容器上:
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
Important
key期望原始值——字符串或数字。不要用对象当 key。
只要有可能就提供 key,除非遍历的 DOM 很简单(没有组件或有状态的 DOM 元素),或者故意用默认行为换性能。
数组变更检测
变异方法
Vue 能检测以下数组变异方法的调用:
| 方法 | 作用 |
|---|---|
push() | 末尾添加 |
pop() | 末尾移除 |
shift() | 开头移除 |
unshift() | 开头添加 |
splice() | 增删改 |
sort() | 排序 |
reverse() | 反转 |
替换数组
非变异方法(filter()、concat()、slice())不改变原数组,返回新数组。需要把旧数组替换成新的:
items.value = items.value.filter((item) => item.message.match(/Foo/))
Vue 会智能复用 DOM 元素,不会整个重新渲染。
显示过滤/排序结果
想显示过滤或排序后的数组,但不改原数据?用计算属性:
const numbers = ref([1, 2, 3, 4, 5])
const evenNumbers = computed(() => {
return numbers.value.filter((n) => n % 2 === 0)
})
<li v-for="n in evenNumbers">{{ n }}</li>
计算属性不可行时(比如嵌套 v-for 里),用方法:
function even(numbers) {
return numbers.filter((number) => number % 2 === 0)
}
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)">{{ n }}</li>
</ul>
Warning计算属性里用
reverse()和sort()会修改原数组!先复制一份:[...numbers].reverse()。
本节回顾
v-for遍历数组、对象、范围key帮 Vue 追踪节点身份,尽量提供- 数组变异方法自动触发更新
- 非变异方法要替换数组
- 过滤/排序结果用计算属性