首页 / Vue3 入门教程 / 列表渲染

Vue3 入门教程

列表渲染

本教程共 40 篇 · 第 9 篇 · 更新于 2026-07-29 · 约 7 分钟阅读

VueVue3 入门教程v-forkey列表渲染数组检测

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 追踪节点身份,尽量提供
  • 数组变异方法自动触发更新
  • 非变异方法要替换数组
  • 过滤/排序结果用计算属性