vue侧栏菜单的无限嵌套

先看效果:
在这里插入图片描述

在权限管理中,可更改任意菜单的路由路径(path)、组件(component)、重定向(redirect) 等属性,也可自定义权限(菜单) 的层级关系(在本文中权限与菜单的意义是一样的)
在这里插入图片描述

如何实现该方案:

将所有的路由对象都存放在数据库中,在每次加载页面前去获取菜单数组,菜单数组需要赋值给两个组件,一个是页面侧栏 el-menu ,一个则是 vue-router;在第一张图的权限管理页面中又是一次独立的查询,不管菜单隐藏或禁用与否,全部查出来。

el-menu 负责展示(其中el-menu需进行递归);在赋值 vue-router 之前也需要递归加载 component,如果component 不存在,则赋一个<router-view/>,如果某个菜单下有子菜单,则该菜单的 component 一定为<router-view/>

demo git地址,分支为 release-1.0

代码细节部分:

router.js 在该js中定义了获取菜单与递归加载 component 的方法

// 定义初始的路由对象,systemFrame页面中定义了侧栏与其他控件
// 不能被用户改变的路由对象都应放在内
const defaultRouter = [{
  _id: 'systemFrame',
  component: () => import('../components/systemFrame'),
  hidden: true,
  name: 'systemFrame',
  path: '/',
  iconCls: 'el-icon-s-tools',
}];

const getRouter = () => new Promise((resolve) => {
  axiosUtil.postPromise('/system/menu/getMenu', {查询条件})
    .then((response) => {
      resolve(recursionSetTemplate(response.data, []));
    })
    .catch((error) => {
      throw error;
    });
});

const template = { template: '<router-view/>' };

/**
 * 递归给路由对象赋予 component
 * 并组装新路由数组array,array传入时为空数组
 * 方法走完后array数据结构会与router一致
 */
const recursionSetTemplate = (router, array) => {
  router.forEach((item) => {
    const newRouter = {
      _id: item._id,
      name: item.name,
      path: item.path,
      redirect: item.redirect,
      hidden: item.hidden,
      menuStatus: item.menuStatus,
      iconCls: item.iconCls,
      noDropdown: item.noDropdown,
    };

    if (!item.children && item.component) {
      newRouter.component = () => import(`@/components/${item.component}`);
    } else {
      newRouter.component = template;
    }
    array.push(newRouter);
      
    if (item.children) {
      newRouter.children = [];
      recursionSetTemplate(item.children, newRouter.children);
    }
  });
  return array;
};

export { getRouter, defaultRouter };

main.js 在该 js 中将路由挂载到 vue-router 中

import Router from 'vue-router';
import Vue from 'vue';
import App from './App.vue';
import { getRouter, defaultRouter } from './router/router';

Vue.use(Router);

Vue.config.productionTip = false;

const router = new Router();

// 添加默认路由规则
router.addRoute(defaultRouter[0]);

getRouter().then((vueRouters) => {
  for (const item of vueRouters) {
    // 将item作为systemFrame的子路由
    router.addRoute('systemFrame', item);
  }
});

router.beforeEach((to, from, next) => {
  next();
});

new Vue({
  router,
  render: (h) => h(App),
}).$mount('#app');

systemFrame.vue 在页面中将路由数组赋值给侧栏

<template>
  <el-container style="height: 700px; border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <el-menu :default-active="$route.path" router>
          <!-- menu-list为该页面子组件,递归展示菜单 -->
        <menu-list v-if="vueRouters.length > 0" :routers="vueRouters"></menu-list>
      </el-menu>
    </el-aside>

    <el-container>
         ...
        <router-view/>
    </el-container>
  </el-container>
</template>

<script>
import menuList from './menuList';
import axiosUtil from '../utils/axiosUtil';

export default {
  name: 'container',
  components: {
    menuList,
  },
  data() {
    return {
      vueRouters: [],
    };
  },
  mounted() {
    axiosUtil.postPromise('/system/menu/getMenu', {查询对象})
      .then((response) => {
        this.vueRouters = response.data;
      });
  },
};
</script>

menuList.vue

<template>
  <div>
    <template v-for="(element) of routers">
      <el-submenu v-if="element.children && !element.hidden && element.menuStatus"
                  :index="element._id" :key="element._id">
        <template slot="title">
          <i :class="element.iconCls"/>
          {{ element.name }}
        </template>
        <menu-list :routers="element.children"></menu-list>
      </el-submenu>
      <el-menu-item v-else-if="!element.hidden && element.menuStatus"
                    :key="element._id" :index="element.path">
        <template slot="title">
          <i :class="element.iconCls"/>
          {{ element.name }}
        </template>
      </el-menu-item>
    </template>
  </div>
</template>
<script>
export default {
  name: 'menuList',
  props: {
    routers: {
      type: Array,
      default: () => [],
    },
  },
};
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值