el-menu导航菜单的二次封装(递归组件)实现动态多级菜单

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: el-menu导航菜单的二次封装(递归组件)实现动态多级菜单

问题描述

在后台管理项目中,牵涉到权限的东西多数是后端传递过来的数据,前端去展示(当然前端也会做一些控制)。就导航菜单而言,也不能写死了,需要在用户登录了以后,发请求获取用户的对应菜单数据,根据对应的数据去展示对应的菜单。

本文记录一下使用组件递归的方式,封装一个动态的、多级的导航菜单,从而实现动态效果。

看这篇文章之前,可以看看我之前的《vue组件的递归自调用~代码思路分析》文章,本篇文章是之前文章的延伸。地址如下: https://juejin.cn/post/7014130015902105636

效果图

我们先看一下效果图:

22.gif

思路分析

  • 首先,我们要和后端沟通返回的数据格式,我们知道前端的el-menu菜单的核心数据属性有四个:

    • 菜单的名字name
    • 点击菜单进行路由跳转的路径path
    • 菜单上小图标icon
    • 菜单是不是最内层的菜单,即children是否是空数组,当children为空的时候,就说明到菜单最里层了。(最里层的菜单children为空数组的时候,点击的时候,做路由跳转)
  • 所以需要有name、path、icon、children属性,且得是一个树结构的格式,和左侧导航菜单保持一致。
  • 这里我们模拟一下后端返回的代码

后端返回的el-menu菜单数据

menuArr: [
    {
// 注意!注意!有children的菜单项,path不会使用的,所以path为什么都无所谓;没children的,即children的length等于0的,才会使用path属性做路由跳转
      name: "前端三大框架",
      path: "前端三大框架", 
      icon: "el-icon-star-off",
      children: [
        {
          name: "vue页面",
          path: "/vue",
          icon: "el-icon-star-off",
          children: [],
        },
        {
          name: "react页面",
          path: "/react",
          icon: "el-icon-star-off",
          children: [],
        },
        {
          name: "angular页面",
          path: "/angular",
          icon: "el-icon-star-off",
          children: [],
        },
      ],
    },
    {
      name: "后端两大框架",
      path: "后端两大框架",
      icon: "el-icon-star-off",
      children: [
        {
          name: "Spring Boot页面",
          path: "/springBoot",
          icon: "el-icon-star-off",
          children: [],
        },
        {
          name: "Spring页面",
          path: "Spring页面", 
          icon: "el-icon-star-off",
          children: [
            {
              name: "MySql页面",
              path: "/mysql",
              icon: "el-icon-star-off",
              children: [],
            },
            {
              name: "Redis页面",
              path: "/redis",
              icon: "el-icon-star-off",
              children: [],
            },
          ],
        },
        {
          name: "Mybatis页面",
          path: "/mybatis",
          icon: "el-icon-star-off",
          children: [],
        },
      ],
    },
  ]
我们先看一下非动态多级菜单的写法,然后再看一下递归组件动态多级菜单的写法

非动态多级菜单(写死了,不灵活,不建议使用)

<el-menu
  :default-active="activeIndex"
  class="elMenu"
  background-color="#333"
  text-color="#B0B0B2"
  active-text-color="#fff"
  :unique-opened="true"
  router
  ref="elMenu"
  @select="menuSelect"
>

  <el-submenu index="非叶子节点也需要index属性">
    <template slot="title">
      <i class="el-icon-star-off"></i>
      <span>前端三大框架</span>
    </template>
    <!-- 这个是没子节点的 没有子内容,用el-menu-item结构 -->
    <el-menu-item index="/vue">
      <i class="el-icon-star-off"></i>
      <span slot="title">vue页面</span>
    </el-menu-item>
    <el-menu-item index="/react">
      <i class="el-icon-star-off"></i>
      <span slot="title">react页面</span>
    </el-menu-item>
    <el-menu-item index="/angular">
      <i class="el-icon-pear"></i>
      <span slot="title">angular页面</span>
    </el-menu-item>
  </el-submenu>
  
  <el-submenu index="非叶子节点也需要index属性哦">
    <template slot="title">
      <i class="el-icon-star-off"></i>
      <span>后端两大框架</span>
    </template>
    <el-menu-item index="/springBoot">
      <i class="el-icon-star-off"></i>
      <span slot="title">Spring Boot页面</span>
    </el-menu-item>

      <!-- 注意看这里有子节点的无子节点的html标签的区别 -->

      <!-- 这个是有子节点的 还有子内容,用el-submenu结构-->
      <el-submenu index="非叶子节点也需要index属性哈">
          <template slot="title">
            <i class="el-icon-star-off"></i>
            <span>Spring页面</span>
          </template>
          <el-menu-item index="/mysql">
            <i class="el-icon-star-off"></i>
            <span slot="title">MySql页面</span>
          </el-menu-item>
          <el-menu-item index="/redis">
            <i class="el-icon-star-off"></i>
            <span slot="title">Redis页面</span>
          </el-menu-item>
      </el-submenu>

      <!-- 这个是没子节点的 没有子内容,用el-menu-item结构 -->
      <el-menu-item index="/mybatis">
          <i class="el-icon-star-off"></i>
          <span slot="title">Mybatis页面</span>
      </el-menu-item>

  </el-submenu>
</el-menu>

发现规律

通过上述代码,我们发现,el-menu代码大致分为两类,有子集和没有子集的

  • 有子集:用的是el-submenu标签包template标签指定名字跟很多个el-menu-item标签
  • 没子集:直接用很多个el-menu-item标签
得出上述规律,我们就能使用递归组件方式去封装一个动态菜单

动态菜单代码

外层菜单部分

html部分

<el-menu
  :default-active="activeIndex"
  class="elMenu"
  background-color="#333"
  text-color="#B0B0B2"
  active-text-color="#fff"
  :unique-opened="true"
  router
  ref="elMenu"
  @select="menuSelect"
>

  <!-- 递归动态菜单 -->
  <myitem :data="menuArr"></myitem>

</el-menu>

js部分

import myitem from "./components/myitem.vue"; // 引入递归菜单组件
export default {
  name: "Home",
  components: {
    myitem, // 注册一下
  },
  data() {
    return {
      activeIndex: this.$route.path,
      menuArr: [...] // 数据是上述我们模拟的数据,#后端返回的el-menu菜单数据#
    };
  }
};

内层递归菜单项部分

<template>
  <div>
    <template v-for="(item, index) in data">
      <!-- 因为有子集和无子集渲染html标签不一样,所以要分为两种情况
           情况一:有子集的情况:                         -->
      <el-submenu
        :key="index"
        :index="item.path"
        v-if="item.children.length > 0"
      >
        <template slot="title">
          <i :class="item.icon"></i>
          <span>{{ item.name }}</span>
        </template>
        <myitem :data="item.children"></myitem>
      </el-submenu>
      <!-- 情况二:没子集的情况: -->
      <el-menu-item :key="index" v-else :index="item.path">
        <i :class="item.icon"></i>
        <span slot="title">{{ item.name }}</span>
      </el-menu-item>
    </template>
  </div>
</template>

<script>
export default {
  name: "myitem",
  props: {
    data: {
      type: Array,
      default: [],
    },
  },
  // 注意: 在template标签上使用v-for,:key="index"不能写在template标签上,因为其标签不会被渲染,会引起循环错误
};
</script>

完整代码

完整代码我上传到Gitee上去了,欢迎大家下载查看,这样更加方便理解。

地址:https://gitee.com/ah-shuai/dynamic-menu

相关文章
Element UI之el-tabs的样式修改字体颜色、下划线、选中/未选中
Element UI之el-tabs的样式修改字体颜色、下划线、选中/未选中
3351 0
element-ui 里 el-popover 位置发生偏移
element-ui 里 el-popover 位置发生偏移
2241 0
|
JavaScript 前端开发 数据安全/隐私保护
vue3+ts+elementplus写一个登录页面教程
【6月更文挑战第3天】本文介绍了如何使用 Vue 3 和 TypeScript 创建一个登录页面。首先,需安装 Vue CLI,然后创建新项目并启用 TypeScript 支持。接着,创建 `Login.vue` 组件,设计登录表单,包括用户账号、密码和验证码字段,并实现相关验证规则。页面样式包括背景、登录框和按钮等元素的布局与样式。最后,展示了`&lt;script&gt;`部分的代码,包括表单验证逻辑、生成验证码的函数以及登录提交处理。文章还提供了一个登录页面的截图和完整代码示例。
5182 1
|
前端开发
element菜单组件样式修改NavMenu导航菜单
本文介绍了如何修改Element UI的NavMenu导航菜单组件的样式,包括激活菜单项的颜色、菜单项hover颜色、父级菜单hover颜色以及菜单行高。提供了相应的CSS代码示例,并展示了如何将这些样式应用到实际的NavMenu组件中。
1137 3
element菜单组件样式修改NavMenu导航菜单
|
JavaScript
vue element-ui 中el-message重复弹出问题解决 el-message重复弹出解决办法
vue element-ui 中el-message重复弹出问题解决 el-message重复弹出解决办法
799 49
|
前端开发 虚拟化
简单记录使用 ElementPlus 的虚拟化树形控件(el-tree-v2)心得
这篇文章分享了作者使用ElementPlus的虚拟化树形控件`el-tree-v2`的心得,展示了其基本用法和如何通过自定义模板来增强树节点的交互性。
3739 1
简单记录使用 ElementPlus 的虚拟化树形控件(el-tree-v2)心得
|
JavaScript
基于Vue2或Vue3实现任意上下左右拖拽悬浮的元素,且配置为自定义的全局指令
这篇文章介绍了如何在Vue 2或Vue 3项目中实现一个自定义的全局指令`v-dragSwitch`,用于创建可以任意方向拖拽并悬浮的元素,同时包含边界处理的逻辑。
3555 2
基于Vue2或Vue3实现任意上下左右拖拽悬浮的元素,且配置为自定义的全局指令
|
12月前
|
资源调度 JavaScript 前端开发
在 Vue 3 中实现流畅的 Swiper 滑动效果
本文介绍了如何在 Vue 3 项目中集成 Swiper,涵盖了从安装、基本用法到丰富的配置选项。通过简单的示例,读者将学习如何创建响应式的图片轮播,利用 Swiper 的循环、自动播放和自定义分页功能,提升用户体验。无论是简单的幻灯片还是复杂的滑块效果,Swiper 都能轻松实现,帮助开发者快速构建出美观的滑动组件。
2313 0
|
前端开发 Java
后端BUG系列之:SpringBoot上传文件太大 报错 Maximum upload size exceeded
这篇文章讨论了SpringBoot应用中上传文件过大导致的错误"Maximum upload size exceeded",并提供了通过修改`application.properties`文件中的上传限制配置来解决这个问题的方法。
|
存储 JavaScript 前端开发
vue前端自适应布局,一步到位所有自适应
【8月更文挑战第9天】在Vue前端实现全面自适应布局颇具挑战,但可通过多种方法达成接近目标的效果。首先,结合BootstrapVue或Element UI等响应式框架简化布局实现过程;其次,利用Sass或Less等预处理器增强CSS编写灵活性;再者,发挥Vue的响应式特性,动态调整组件尺寸与位置;同时采用Flexbox及媒体查询技术确保不同屏幕尺寸下的一致体验;针对移动设备,采取移动优先策略并使用专门框架优化表现;最后,多平台测试与细致调优保证布局效果。综合运用上述策略,可在复杂多变的设备环境中打造近乎完美的自适应布局。
780 1