Vue 3 树形菜单需递归组件+条件渲染,须显式声明 name(如 defineOptions({ name: 'TreeItem' })),通过 v-for 遍历子节点、v-if 判断 children 存在,key 必用唯一 id,建议加深度限制防无限递归。

在 Vue 3 模板中遍历生成多层级树形菜单,核心是**递归组件 + 条件渲染**,不依赖第三方库也能原生实现。关键不是“写更多 v-for”,而是让组件能调用自己。
递归组件必须声明 name
Vue 3 要求递归组件在 defineOptions 或 export default 中显式声明 name,否则模板里无法自引用:
defineOptions({ name: 'TreeItem' })
之后模板中才能安全使用 <treeitem></treeitem> 调用自身,这是递归成立的前提。
立即学习“前端免费学习笔记(深入)”;
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
用 v-for + v-if 实现层级展开逻辑
每个节点渲染自身内容,并判断是否有子节点;有则递归传入子数据继续渲染:
- 用
v-for="child in node.children"遍历当前层子项 - 用
v-if="node.children?.length"控制是否渲染子级区域(避免空数组报错) - 子级组件接收的 props 必须是单个节点对象(如
:node="child"),不是整个数组
示例片段:
<template>
<div class="tree-node">
<span>{{ node.label }}</span>
<ul v-if="node.children?.length">
<TreeItem
v-for="child in node.children"
:key="child.id"
:node="child"
/>
</ul>
</div>
</template>
注意 key 的取值方式
递归中每一层的 v-for 都需要唯一、稳定、层级无关的 key:
- 不能用
:key="index"—— 会导致状态错乱、动画异常 - 应使用节点自身唯一标识,如
:key="node.id"或:key="node.value" - 如果后端未提供 id,可用
crypto.randomUUID()在数据初始化时补全(不建议运行时生成)
避免无限递归和性能问题
即使结构合法,也要主动设防:
- 加深度限制:在组件内用
props.depth计数,超过 10 层直接 return 空内容 - 用
v-show替代v-if控制子树显隐(适合频繁切换场景) - 对大数据量节点,可结合
IntersectionObserver做可视区懒加载(需额外封装)

















