vue基于后台返回路由表动态加载左侧菜单

125 阅读2分钟

作为后端的CV工程师,此篇文章第一次写关于vue的文章,术业有专攻,倘若有前端开发者发现此篇文章有哪里不当之处,望君指出,不胜感激!

首先静态路由部分

import Vue from 'vue'
import Router from 'vue-router'
import Layout from '../layout'

Vue.use(Router)

var constantRouterMap=[
  {path: '/', name: 'Login',hidden:true, component: resolve => require(['@/views/Login'], resolve)},
  {
    path: '/index',
    name: 'Layout',
    component: Layout,
    redirect:'/home',
    children: [{
      path: '/home',
      name: 'Home',
      component: () => import('../views/Home'),
      meta: {
        title: '首页',
        icon: 'vue-dsn-icon-zhuye',
        fixed: true
      }
    }]
  },
  {
    path: '/chat',
    name: '聊天公告',
    component: Layout,
    hidden:true,
    redirect:'/chatmassage',
    children: [{
      path: '/chatmassage',
      name: 'chatmassage',
      component: () => import('../views/Chats/Chat'),
      meta: {
        title: '聊天公告'
      }
    }],
  }
];



export default new Router({
  model:'hash',
  routes: constantRouterMap
})

处理动态路由部分

const _import = require('../router/_import_' + process.env.NODE_ENV) //获取组件的方法
import { GetMenuList} from "@/utils/api";
import Layout from '../layout'

let getRouter //用来获取后台拿到的路由

export const initMenu = (router, store)=> {
  if(!getRouter) {
    if (store.state.routes.length > 0) {
      return;
    }
    GetMenuList().then(resp => {
      if (resp && resp.status == 200) {
        getRouter=resp.data.menus;
        getRouter = filterAsyncRouter(getRouter) //过滤路由
        router.addRoutes(getRouter) //动态添加路由
        store.commit('initMenu', getRouter);
      }
    }).finally(() => {

    })
  }
}

function filterAsyncRouter(asyncRouterMap) { //遍历后台传来的路由字符串,转换为组件对象
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === "Layout") { //Layout组件特殊处理
        route.component = Layout
      } else {
        route.component = _import(route.component)
      }
    }
    if (route.children && route.children.length>0) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })
  return accessedRouters
}

_import_production.js如下:

module.exports = file => () => import('@/views/' + file + '.vue')

然后在路由守卫中初始化左侧菜单

router.beforeEach((to, from, next) => {
  let Token = localStorage.getItem("authorization")
  if(to.path === '/'){
    return next()
  }
  if (!Token && to.path !== '/') {
    return next('/')
  }else {
    initMenu(router, store);
    if(to.path=='/chat')
      store.commit("updateMsgList", []);
    next();
  }
});

后台返回数据如下:

[{	"name": "组织管理",	"path": "/organization",	"children": [{		"name": "菜单权限管理",		"path": "/menus",		"component": "Users/User",		"meta": {			"icon": "",			"title": "菜单权限管理"		}	}, {		"name": "用户管理",		"path": "/user",		"component": "Users/User",		"meta": {			"icon": "",			"title": "用户管理"		}	}, {		"name": "角色管理",		"path": "/index/roles",		"component": "Users/User",		"meta": {			"icon": "",			"title": "角色管理"		}	}],
	"component": "Layout",
	"meta": {
		"icon": "vue-dsn-icon-drxx10",
		"title": "组织管理"
	}
}, {
	"name": "系统管理",
	"path": "/system",
	"children": [{
		"name": "日志管理",
		"path": "/logs",
		"component": "System/Logs/OperatingLog/Index",
		"meta": {
			"icon": "",
			"title": "日志管理"
		}
	}, {
		"name": "接口管理",
		"path": "/swagger",
		"component": "System/Swagger/Index",
		"meta": {
			"icon": "",
			"title": "接口管理"
		}
	}, {
		"name": "SQL监控",
		"path": "/druid",
		"component": "System/Druid/Index",
		"meta": {
			"icon": "",
			"title": "SQL监控"
		}
	}],
	"component": "Layout",
	"meta": {
		"icon": "vue-dsn-icon-GitHub",
		"title": "系统管理"
	}
}, {
	"name": "文件系统",
	"path": "/files",
	"children": [{
		"name": "我的文件",
		"path": "/index/files",
		"component": "Users/User",
		"meta": {
			"icon": "",
			"title": "我的文件"
		}
	}, {
		"name": "轮播图管理",
		"path": "/index/rotations",
		"component": "Users/User",
		"meta": {
			"icon": "",
			"title": "轮播图管理"
		}
	}],
	"component": "Layout",
	"meta": {
		"icon": "vue-dsn-icon-zhbg-file",
		"title": "文件系统"
	}
}]

Layout部分参照花裤衩大神的布局

<template>
  <div class="side-menu-wrapper">
    <el-scrollbar wrap-class="scrollbar">
      <el-menu
        :default-active="activeMenu"
        :collapse="collapsed"
        :unique-opened="true"
        background-color="#263238"
        text-color="#fff"
        active-text-color="#409eff"
      >
        <SideMenuItem
          v-for="route in routes"
          :key="route.path"
          :item="route"
          :base-path="route.path"
        />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
  import { mapGetters } from 'vuex'
  import SideMenuItem from './SideMenuItem'
  export default {
    name: 'SideMenu',
    components: { SideMenuItem },
    computed: {
      ...mapGetters('app', ['collapsed']),
      routes() {
        return this.$router.options.routes.concat(this.$store.state.routes)
      },
      activeMenu() {
        const route = this.$route
        const { meta, path } = route
        if (meta.activeMenu) {
          return meta.activeMenu
        }
        return path
      }
    },
  }
</script>

<style lang="less">
  @import "../../../assets/less/side-menu";
</style>

效果如下:

在这里插入图片描述