Vue3 怎么遍历组件里的所有项?几种做法一次讲清

编程狮(w3cschool.cn) 2026-11-06 07:06:53 浏览数 (30)
反馈

在 Vue3 里遍历一个组件渲染出来的所有项,最稳的做法是用 v-for 把数据数组直接映射成 DOM 节点;当数据需要先过滤或排序时,放到计算属性里处理,而不是把逻辑写进模板。本文先给结论,再讲三种常见写法,帮你按数据形状和交互需求挑最合适的那一种。

Vue3 遍历组件项封面

很多新手一拿到列表就直接在模板里硬写 v-for,遇到嵌套、过滤、排序就开始在模板里堆逻辑,结果模板又长又难维护,出错了还很难定位。其实“遍历组件里的项”可以拆成“数据怎么准备”和“模板怎么渲染”两步。下面用一个“标签列表”的场景,把三种写法一次讲清。

所谓遍历组件里的项,本质是“一个数组”如何变成“一排可交互的 DOM 节点”:是原样渲染,还是先加工再渲染,以及遇到不知道层级的嵌套结构时怎么兜底。把这三点想清楚,写法自然就清晰了。

先看结论

遍历组件里的项,优先用 v-for 直接渲染原始数组;需要过滤、排序、去重时,先用计算属性加工数据再遍历;遇到不知道层级的嵌套结构,用递归组件或递归函数逐层遍历。判断标准是“数据要不要先变样、结构是不是嵌套的”,据此选写法,模板就能始终只负责渲染干净的数据。

一、最小场景与预期行为

假设我们有一个标签管理组件,父组件传进来的 props.tags 是一个数组,比如 [{id:1, name:'Vue3', active:true}, {id:2, name:'Vite', active:false}]。我们要把它渲染成一排标签,并且只显示 active 为 true 的项;如果某些标签带有 children,还要把子项也展开渲染。

明确这个预期,就能反推出要用的写法:普通数组用 v-for 直接渲染,过滤用计算属性,嵌套用递归。Vue3 的单文件组件写法可以看 Vue3 教程 打基础,下面直接在示例里展开三种写法。这个最小场景里最容易混淆的是「渲染」和「加工」两件事:新手常把过滤、排序逻辑写进模板,导致模板膨胀难维护。先把数据层和处理层分开,是后面三种写法共通的主线。

二、写法一:v-for 直接遍历渲染(最常用)

最稳、最通用的写法,是直接对数组用 v-for:

<template>
  <ul>
    <li v-for="tag in tags" :key="tag.id">{{ tag.name }}</li>
  </ul>
</template>

这里有几个遍历组件的要点。第一,:key 必须用稳定且唯一的字段(如 tag.id),不要用数组下标,否则在增删项时会出现节点复用错乱;第二,v-for 渲染出来的每一项都是一个独立的 DOM 节点,可以单独绑定事件;第三,如果只想要 active 的项,不要在模板里把 v-if 和 v-for 写在同一节点——Vue3 中 v-if 优先级更低,会拿不到 item,正确做法是先在数据层过滤。想系统练一遍可以跟 Vue3 课程 的示例走。

Vue3 遍历组件项的写法怎么选?

三、写法二:用计算属性预处理后再遍历

第二种常见需求是“先加工再渲染”。与其在模板里又 v-for 又 v-if,不如把过滤逻辑放进计算属性,模板只负责遍历组件渲染加工后的结果:

<script setup>
import { computed } from 'vue'
const props = defineProps({ tags: Array })
const activeTags = computed(() =>
  props.tags.filter(t => t.active).sort((a, b) => a.order - b.order)
)
</script>
<template>
  <li v-for="tag in activeTags" :key="tag.id">{{ tag.name }}</li>
</template>

这种写法把“数据怎么准备”和“模板怎么渲染”彻底分开。在 Vue3 遍历组件列表时,模板永远拿到干净的组件列表,过滤、排序、去重都在 computed 里完成,可读性和可测试性都更好。注意 computed 是带缓存的,只有依赖变化才重算,比在模板里每次都跑函数更省。遍历出来的每一项往往来自后端接口返回的数据;若你的服务端用 Java 写,可以常备一份 Spring 速查手册 对照字段含义,避免前后端字段对不上。

Vue3 遍历三个易错点

四、写法三:递归遍历嵌套组件项与边界

当 tags 里某些项带 children,而且层级不固定时,普通 v-for 就不够了。两个做法:一是写递归组件(组件自己引用自己),二是在一个递归函数里把嵌套拍平成一层再 v-for。

<!-- TagNode.vue 递归组件 -->
<template>
  <div>
    <span>{{ node.name }}</span>
    <TagNode v-for="child in node.children" :key="child.id" :node="child" />
  </div>
</template>
<script setup>
defineProps({ node: Object })
</script>

递归遍历组件项最容易踩的坑是“没有终止条件导致栈溢出”:必须保证 children 为空时不再渲染自己。另一个边界是“同一份数据被不同层级引用造成无限循环”,遍历前先确认数据结构是无环的。响应式渲染方面,嵌套数据要用 reactive/ref 包好,深层改动能被 Vue3 的响应式系统追踪到,否则界面不会更新。

动手验证清单

想确认你的遍历真的可用,可以按下面步骤验证:

  • 安装/配置:用 npm create vue@latest 创建 Vue3 项目,在组件里写 <script setup>。
  • 运行:npm run dev 打开页面,确认标签列表正常渲染。
  • 检查:切换 active 状态,过滤后的列表应实时变化;改 children 数据,嵌套应正确展开。
  • 预期:v-for 渲染的项可点击、可筛选,嵌套能递归展开不报错。
  • 验证:故意删掉 :key 看复用错乱,再加回稳定 key 对比差异。
  • 失败处理:若列表不更新,检查数据是否被 reactive 包裹;若递归爆栈,确认 children 为空时停止递归。
  • 注意:以上示例基于 Vue3 最新稳定版,未在浏览器逐条运行,请以你的实际版本为准。

常见问题

Q:v-for 和 v-if 能写在同一节点吗?

不推荐。Vue3 中 v-if 优先级低于 v-for,写在同节点时 v-if 访问不到 v-for 的变量,会报错或失效。正确做法是先把过滤逻辑放到计算属性,再对结果做 v-for 遍历组件列表。

Q:遍历时 key 用下标为什么会有 bug?

因为下标在数据增删后会错位,Vue 的 diff 可能复用错误的 DOM 节点,导致输入框内容串台、勾选状态错乱。始终用数据里稳定唯一的字段(如 id)做 key。

Q:嵌套数据怎么遍历才不爆栈?

用递归组件或递归函数时,必须保证“没有子节点就停止递归”这一终止条件;同时要确认数据结构无环。响应式渲染的嵌套数据要用 reactive/ref 包裹,保证深层变更能被追踪。

inline

总结

在 Vue3 里遍历组件里的所有项,记住三档写法:普通数组用 v-for 直接渲染;需要过滤、排序、去重时,先用计算属性加工数据再遍历;遇到不确定层级的嵌套结构,用递归组件或递归函数逐层遍历。核心判断标准是“数据要不要先变样、结构是不是嵌套的”。把“数据准备”和“模板渲染”分开,代码更清晰也更省性能。

延伸学习

0 人点赞