el-menu根据多层树形结构递归遍历展示菜单栏

news2024/11/25 10:31:58

文章目录

  • 前提条件
  • 假设菜单等级只有两个等级
    • 结果如下所示
  • 但是如果菜单等级超过两个等级或者多个等级的话
    • App.vue
    • MenuItems.vue
    • 结果如下所示
  • 关于遍历时图标前的展示后续完善
  • 关于点击路由跳转参考element plus的官网即可

前提条件

package.json如下所示,这是一个Vite + Vue3 + TS的项目

{
  "name": "vue3-ts-vite-wen-zhang-ji-lu-xiang-mu",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "element-plus": "^2.4.2",
    "vue": "^3.3.4"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.2.3",
    "sass": "^1.69.5",
    "typescript": "^5.0.2",
    "vite": "^4.4.5",
    "vue-tsc": "^1.8.5"
  }
}

下面为了方便,直接在App.vue组件中,代码结构如下所示,就一纯净项目,然后直接在App.vue中写代码
在这里插入图片描述

假设菜单等级只有两个等级

如果菜单等级只有两个等级,那就没有必要使用到递归了,直接遍历,然后根据是否有children字段,判断是一级菜单还是二级菜单就可以了。具体代码如下所示:

<template>
  <div style="width: 100%; height: 100%;">
    <div class="common-layout">
      <el-container>
        <el-header>头部</el-header>
        <el-container>
          <!-- 侧边栏区域 -->
          <el-aside width="200px">
            <el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose">
              <template v-for="(item, index) in menuList" :key="index">
                <el-sub-menu :index="item.path" v-if="item.children && item.children.length">
                  <template #title>
                    <el-icon>
                      <location />
                    </el-icon>
                    <span>{{ item.name }}</span>
                  </template>
                  <el-menu-item v-for="child in item.children" :key="child.id" :index="child.path">
                    {{ child.name }}
                  </el-menu-item>
                </el-sub-menu>
                <el-menu-item v-else :index="item.path">
                  <el-icon><setting /></el-icon>
                  <span>{{ item.name }}</span>
                </el-menu-item>
              </template>
            </el-menu>
          </el-aside>
          <!-- 主题区域 -->
          <el-main>
            这是主题区域
          </el-main>
        </el-container>
      </el-container>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { Location, Setting } from '@element-plus/icons-vue'

interface MenuItem {
  id: number;
  name: string;
  path: string;
  icon?: string;
  component?: string;
  children?: MenuItem[];
}

const menuList = ref<MenuItem[]>(
  [
    {
      id: 1,
      name: '首页',
      path: '/',
      icon: 'location',
      component: 'home',
      children: []
    },
    {
      id: 2,
      name: '用户管理',
      path: '/user',
      icon: 'location',
      component: 'user',
      children: [
        {
          id: 3,
          name: '用户列表',
          path: 'list',
          icon: '',
          component: 'userList',
          children: []
        },
        {
          id: 5,
          name: '角色列表',
          path: 'roleList',
          icon: '',
          component: 'userList',
          children: []
        }
      ]
    },
    {
      id: 6,
      name: '权限管理',
      path: '/permission',
      icon: 'setting',
      component: 'permission',
      children: [
        {
          id: 7,
          name: '权限列表',
          path: 'permissionList',
          icon: '',
          component: 'permissionList',
        }
      ]
    }
  ]
)

const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}

</script>


<style scoped lang="scss">
.el-container {
  width: 100%;
  height: 100%;
}
</style>

结果如下所示

在这里插入图片描述

但是如果菜单等级超过两个等级或者多个等级的话

但是如果菜单等级超过两个等级或者多个等级的话,这时就可以使用到组件递归的方式进行了。目录结构如下所示:
在这里插入图片描述

App.vue

<template>
  <div style="width: 100%; height: 100%;">
    <div class="common-layout">
      <el-container>
        <el-header>头部</el-header>
        <el-container>
          <!-- 侧边栏区域 -->
          <el-aside width="200px">
            <el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose">
              <menu-items :items="menuList"></menu-items>
            </el-menu>
          </el-aside>
          <!-- 主题区域 -->
          <el-main>
            这是主题区域
          </el-main>
        </el-container>
      </el-container>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import MenuItems from './components/MenuItems.vue'

interface MenuItem {
  id: number;
  name: string;
  path: string;
  icon?: string;
  component?: string;
  children?: MenuItem[];
}

const menuList = ref<MenuItem[]>(
  [
    {
      id: 1,
      name: '首页',
      path: '/',
      icon: 'location',
      component: 'home',
      children: []
    },
    {
      id: 2,
      name: '用户管理',
      path: '/user',
      icon: 'location',
      component: 'user',
      children: [
        {
          id: 3,
          name: '用户列表',
          path: 'list',
          icon: '',
          component: 'userList',
          children: [
            {
              id: 4,
              name: '用户详情',
              path: 'userDetail',
              icon: '',
              component: 'userDetail',
              children: []
            }
          ]
        },
        {
          id: 5,
          name: '角色列表',
          path: 'roleList',
          icon: '',
          component: 'userList',
          children: []
        }
      ]
    },
    {
      id: 6,
      name: '权限管理',
      path: '/permission',
      icon: 'setting',
      component: 'permission',
      children: [
        {
          id: 7,
          name: '权限列表',
          path: 'permissionList',
          icon: '',
          component: 'permissionList',
          children: [
            {
              id: 8,
              name: '权限详情-1',
              path: 'permissionDetail',
              icon: '',
              component: 'permissionDetail',
              children: [
                {
                  id: 9,
                  name: '权限详情-2',
                  path: 'permissionDetail2',
                  icon: '',
                  component: 'permissionDetail2',
                  children: []
                }
              ]
            }
          ]
        }
      ]
    }
  ]
)

const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}

</script>


<style scoped lang="scss">
.el-container {
  width: 100%;
  height: 100%;
}
</style>

MenuItems.vue

<template>
    <template v-for="item in items" :key="item.id">
        <el-sub-menu v-if="item.children && item.children.length > 0" :index="item.path">
            <template #title>
                <span>{{ item.name }}</span>
            </template>
            <!-- 递归遍历 -->
            <menu-items :items="item.children" />
        </el-sub-menu>
        <el-menu-item v-else :index="item.path">
            <span>{{ item.name }}</span>
        </el-menu-item>
    </template>
</template>

<script setup lang="ts">
interface MenuItem {
  id: number;
  name: string;
  path: string;
  icon?: string;
  component?: string;
  children?: MenuItem[];
}
defineProps<{
    items: MenuItem[];
}>()
</script>

结果如下所示

在这里插入图片描述
从图中可以看出,无论是一层,二层,三层,四层结构的树形数据,都可以在el-menu中展示。

关于遍历时图标前的展示后续完善

关于点击路由跳转参考element plus的官网即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1941738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

广州邀请媒体宣传(附媒体名单)

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 广州地区 媒体邀约&#xff1a; 记者现场采访&#xff0c;电视台到场报道&#xff0c;展览展会宣传&#xff0c;广交会企业宣传&#xff0c;工厂探班&#xff0c;媒体专访等。 适合广州…

vue3前端开发-小兔鲜项目-二级页面面包屑导航和跳转

vue3前端开发-小兔鲜项目-二级页面面包屑导航和跳转&#xff01;这一次&#xff0c;做两件事。第一件事是把二级分类页面的跳转&#xff08;也就是路由&#xff09;设计一下。第二件事是把二级页面的面包屑导航设计一下。 第一件事&#xff0c;二级页面的跳转路由设计一下。 如…

【RabbitMQ】Windows下RabbitMQ的安装和部署

Windows下RabbitMQ的安装和部署 一、引言二、环境搭建三、安装ERLANG四、安装RabbitMQ五、安装RabbitMQ-Plugins六、验证 一、引言 RabbitMQ——Rabbit Message Queue的简写&#xff0c;但不能仅仅理解其为消息队列&#xff0c;消息代理更合适。RabbitMQ 是一个由 Erlang 语言…

智慧隧道可视化:安全与效率的智能保障

运用图扑可视化技术&#xff0c;实时监测隧道内的环境和交通状况&#xff0c;提升维保效率和应急响应能力&#xff0c;确保隧道运营的安全和畅通。

Build a Large Language Model (From Scratch)GPT-4o翻译和代码每行中文注释Ch5

目录 Pretraining on Unlabeled DataThis chapter covers5.1 Evaluating generative text models5.1.1 Using GPT to generate text5.1.2 Calculating the text generation loss5.1.3 Calculating the training and validation set losses 5.2 Training an LLM5.3 Decoding str…

免费分享一套微信小程序图书馆座位预约管理系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序图书馆座位预约管理系统(SpringBoot后端Vue管理端)&#xff0c;分享下哈。 项目介绍 随着移动互联网技术的飞速发展和智能设备的普及&#xff0c;图书馆服务模式正在经历深刻的变革。本论文旨在…

【Linux】从零开始认识多线程 --- 线程ID

在这个浮躁的时代 只有自律的人才能脱颖而出 -- 《觉醒年代》 1 前言 上一篇文章中讲解了线程控制的基本接口&#xff1a; 线程创建pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);: pthread_t *thread :输出…

艺术成分很高的完全自定义的UITabBar(很简单)

引言 在iOS应用开发中&#xff0c;UITabBar是一个非常场景且重要的UI组件。系统为我们提供的UITabBar虽然功能强大&#xff0c;但是在某些情况下&#xff0c;它的标准样式并不能满足我们特定的设计需求&#xff0c;它的灵活性也有一些局限。为了打造更具个性化好的用户友好的交…

Ai绘画变现的14种途径 学习Stablediffusion midjourney用途

AIGC&#xff0c;一个在当代社会中不可忽视的词汇&#xff0c;指的是利用人工智能技术生成创作内容。近年来&#xff0c;全球范围内涌现出50个热门的AI工具&#xff0c;其中&#xff0c;以140亿次访问量雄踞榜首的“GBT”&#xff0c;无疑是AI领域的领头羊。在这些工具中&#…

node.js中nodemon : 无法加载和使用问题,这是由于windows安全策略影起的按如下操作即可

1、用管理员权限打开vscode 2、文件终端中打开&#xff0c;输入 Set-ExecutionPolicy -Scope CurrentUser 3、再输入RemoteSigned 4、使用get-ExecutionPolicy查看权限&#xff0c;可以看到变为了RemoteSigned 重启问题解决

一个注解解决重复提交问题

一、前言 ​ 在应用系统中提交是一个极为常见的功能&#xff0c;倘若不加管控&#xff0c;极易由于用户的误操作或网络延迟致使同一请求被发送多次&#xff0c;从而生成重复的数据记录。针对用户的误操作&#xff0c;前端通常会实现按钮的 loading 状态&#xff0c;以阻…

【leetcode】排列序列

给出集合 [1,2,3,...,n]&#xff0c;其所有元素共有 n! 种排列。 按大小顺序列出所有排列情况&#xff0c;并一一标记&#xff0c;当 n 3 时, 所有排列如下&#xff1a; "123""132""213""231""312""321" 给定…

构建高效园区导览系统:基于3DGIS与物联网技术的实现方案

园区导航的挑战与机遇 在现代化的大型园区中&#xff0c;随着面积的不断扩张和布局的日益复杂&#xff0c;传统的纸质地图已难以满足日益增长的导航需求。每栋楼、每层楼都有着不同的办公室&#xff0c;不同的业务。这种低效的寻路过程不仅影响了客户的来访体验&#xff0c;也…

介绍一下TCP/IP 模型和 OSI 模型的区别

OSI 模型是由国际标准化组织制定的一个用于计算机或通信系统间互联的标准体系&#xff0c;一共有七层&#xff0c;由上而下分别为应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;网络层&#xff0c;数据链路层和物理层&#xff0c;虽然 OSI 模型理论…

系统架构设计师教程 第4章 信息安全技术基础知识-4.1 信息安全基础知识-解读

系统架构设计师教程 第4章 信息安全技术基础知识-4.1 信息安全基础知识 4.1.1 信息安全的概念4.1.1.1 信息安全的范围4.1.1.1.1 设备安全4.1.1.1.2 数据安全4.1.1.1.3 内容安全4.1.1.1.4 行为安全 4.1.2 信息存储安全4.1.2.1 信息使用的安全4.1.2.1.1 用户的标识与验证4.1.2.1.…

免费【2024】springboot 趵突泉景区的智慧导游小程序

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

监控电脑进程,避免程序在打开前就已经在运行

文章目录 一、文章的目的&#xff08;适用于windows&#xff09;二、处理方式三、进程查看的内容在窗口端的演示四、附上代码例子四、通过os.kill的方式&#xff0c;再回到原来的表格时&#xff0c;会出现如下错误提示&#xff1a; 一、文章的目的&#xff08;适用于windows&am…

Flink笔记整理(三)

Flink笔记整理&#xff08;三&#xff09; 文章目录 Flink笔记整理&#xff08;三&#xff09;五、DataStream API5.1Environment5.2 Source5.3 Transformation5.4 Sink 总结 五、DataStream API DataStream API是Flink的核心层API&#xff0c;一个Flink程序&#xff0c;其实本…

谷粒商城实战笔记-44-前端基础-Vue-整合ElementUI快速开发/设置模板代码

文章目录 一&#xff0c;安装导入ElementUI1&#xff0c;安装 element-ui2&#xff0c;导入 element-ui 二&#xff0c;ElementUI 实战1&#xff0c;将 App.vue 改为 element-ui 中的后台布局2&#xff0c;开发导航栏2.1 开发MyTable组件2.2 注册路由2.3 改造App.vue2.4 新增左…

传统行业 IT 团队数字化转型该如何进行?

一、前言 数字化转型概念&#xff1a; 数字化转型是“以更加数字化的方式重新思考&#xff0c;重新塑造商业。是从根本上考虑交付渠道&#xff0c;运营&#xff0c;市场和销售以及顾客关注——所有的业务模块&#xff0c;并重新思考这些能否包装成新的数字化产品和服务&#…