最近接手一个后台管理项目,需要实现从后台拉取导航菜单的效果;根据不同的登录用户的权限分别拉取不同的导航菜单,进行页面的跳转
实现方法:
从后台返回菜单与动态路由的数组做匹配,选择需要动态加载的路由,在将后台返回的菜单加载到页面即可
1.首先在本地固定配置好不变的路由的地址,例如登录,404,403,500等公用页面
const constantRouterMap = [ { path:'/login', name:'Login', component:Login }, { path: '/', name:'', component:layout, redirect: '/home', children:[ { path:'/home', component:home, name:'首页页面', meta:{ close:false } } ] }, { path: "/500", name: "serverError", component: serverError }, { path: "/403", name: "notPermission", component: notPermission }, { path: "/404", name: "notFound", component: notFound }, { path: "*", // 此处需特别注意置于最底部 redirect: "/404" } ]
2.动态加载的菜单配置
//动态加载的路由 const asyncRouterMap = [ { path:'/sys/user', component:sys_user, name:'用户权限', meta:{ close:true } }, { path:'/sys/sysPermission', component:sys_menu, name:'权限管理', meta:{ close:true } }, { path:'/sys/role', component:sys_role, name:'角色管理', meta:{ close:true } }, { path:'/sys/appMenu', component:sys_dept, name:'菜单管理', meta:{ close:true } }, { path:'/dict', component:dict, name:'字典管理', meta:{ close:true } } ] 3.利用后台返回的菜单的格式 {"code":200,"msg":"success","data":[{"id":"2","isNewRecord":false,"createDate":"2013-05-27 08:00:00","updateDate":"2013-05-27 08:00:00","parentIds":"0,1,","name":"系统设置","sort":900,"isShow":"1","isApp":"0","children":[{"id":"44c896e862264fc883b7dbe35a56ea55","isNewRecord":false,"remarks":"","createDate":"2017-03-06 20:59:16","updateDate":"2017-11-29 14:51:12","parentIds":"0,1,2,","name":"组织机构","href":"","target":"","icon":"","sort":10,"isShow":"1","permission":"","isApp":"0","children":[{"id":"17","isNewRecord":false,"remarks":"","createDate":"2013-05-27 08:00:00","updateDate":"2017-03-06 21:00:01","parentIds":"0,1,2,44c896e862264fc883b7dbe35a56ea55,","name":"机构管理","href":"/sys/office","target":"","icon":"th-large","sort":40,"isShow":"1","permission":"","isApp":"0","children":[],"parentId":"44c896e862264fc883b7dbe35a56ea55"},{"id":"20","isNewRecord":false,"remarks":"","createDate":"2013-05-27 08:00:00","updateDate":"2017-03-06 21:00:29","parentIds":"0,1,2,44c896e862264fc883b7dbe35a56ea55,","name":"人员管理","href":"/sys/user","target":"","icon":"user","sort":50,"isShow":"1","permission":"","isApp":"0","children":[],"parentId":"44c896e862264fc883b7dbe35a56ea55"}],"parentId":"2"},{"id":"3","isNewRecord":false,"createDate":"2013-05-27 08:00:00","updateDate":"2013-05-27 08:00:00","parentIds":"0,1,2,","name":"系统设置","sort":20,"isShow":"1","isApp":"0","children":[{"id":"4","isNewRecord":false,"remarks":"","createDate":"2013-05-27 08:00:00","updateDate":"2017-12-18 11:09:05","parentIds":"0,1,2,3,","name":"PC菜单管理","href":"/sys/webMenu","target":"","icon":"list-ul","sort":30,"isShow":"1","permission":"","isApp":"0","children":[],"parentId":"3"},{"id":"8f0210e672a54b0282d08ce3a9259c66","isNewRecord":false,"remarks":"","createDate":"2017-12-18 10:28:22","updateDate":"2017-12-18 11:09:55","parentIds":"0,1,2,3,","name":"APP菜单管理","href":"/sys/appMenu","target":"","icon":"list","sort":40,"isShow":"1","permission":"","isApp":"0","children":[],"parentId":"3"},{"id":"7","isNewRecord":false,"remarks":"","createDate":"2013-05-27 08:00:00","updateDate":"2017-11-30 13:38:50","parentIds":"0,1,2,3,","name":"角色管理","href":"/sys/role","target":"","icon":"group","sort":50,"isShow":"1","permission":"","isApp":"0","children":[],"parentId":"3"}],"parentId":"2"}],"parentId":"1"}]} 4.通过一个函数将菜单与动态的路由做匹配
export function filterAsyncRouter(asyncRouterMap=[],menuTree=[]){ const res = [] const routers = getRoute(menuTree) asyncRouterMap.forEach((route)=>{ var routeItem = route routers.forEach((item)=>{ if(item.href==routeItem.path){ //将后台返回的name赋值给前台定义好的 routeItem.name = item.name res.push(routeItem) } }) }) return res; }
5.利用路由的addRouter的特性将于菜单匹配到的路由加载到路由中
let asyncRouterMaps = filterAsyncRouter(asyncRouterMap,store.state.navTree)
asyncRouterMaps.forEach((route)=>{ router.options.routes[1].children.push(route) }) router.addRoutes(router.options.routes) 6.再将后台返回的菜单加载到页面中即可: menuTree.vue加载一个菜单的component <template>
<el-submenu v-if="menu.children && menu.children.length >= 1" :index="'' + menu.id"> <template slot="title"> <i :class="menu.icon" ></i> <span slot="title">{{menu.name}}</span> </template> <MenuTree v-for="item in menu.children" :key="item.id" :menu="item"></MenuTree> </el-submenu> <el-menu-item v-else :index="(menu.href?menu.href:menu.id)"> <i :class="menu.icon"></i> <span slot="title">{{menu.name}}</span> </el-menu-item> </template>
在home的navbar中引用到需要的地方即可
<template> <!--导航栏部分--> <aside :class="collapsed?'menu-collapsed':'menu-expanded'"> <el-menu ref="navmenu" :default-active="$router.history.current.path" router unique-opened class="el-menu-vertical-demo" @select="handleSelect" @open="handleOpen" @close="handleClose" :collapse="collapsed"> <menu-tree v-for="item in navTree" :key="item.id" :menu="item"></menu-tree> </el-menu> </aside> </template> <style> .el-menu-vertical-demo:not(.el-menu--collapse) { width: 230px; } </style> <script> import store from '@/store' import router from '@/router' import {mapState} from 'vuex' import MenuTree from '@/components/menuTree' import { setTab,getTab } from '@/utils/auth' export default { data() { return { navTree:this.$store.state.navTree, }; }, components:{ MenuTree }, watch:{ '$route':'handleRoute' }, created () { this.handleRoute(this.$route) }, methods: { handleOpen(key, keyPath) { }, handleClose(key, keyPath) { }, handleSelect(key,keyPath){ }, handleRoute(route){ //标签页选中,如果不存在则先添加 //检查现有的tab标签中是否存在,通过path去判断 var tab = this.mainTabs.filter(item => item.name === route.name)[0] if(!tab){ tab = { name:route.name, title:route.name, path:route.path, close:route.meta.close } this.mainTabs = this.mainTabs.concat(tab) } setTab(this.mainTabs) this.mainTabsActiveName = route.name // 切换标签页时同步更新高亮菜单 if(this.$refs.navmenu != null) { this.$refs.navmenu.activeIndex = route.path this.$refs.navmenu.initOpenedMenu() } } }, computed:{ ...mapState({ collapsed:'collapse', }), mainTabs:{ get () { return this.$store.state.mainTabs }, set (val) { this.$store.commit('getMainTabs', val) } }, mainTabsActiveName: { get () { return this.$store.state.mainTabsActiveName }, set (val) { this.$store.commit('getMainTabsActiveName', val) } } }, mounted(){ } } </script> <style lang="less" scoped>mainTabs aside { flex:0 0 230px; width: 230px; // position: absolute; // top: 0px; // bottom: 0px; .el-menu{ height: 100%; background: #eef1f6; } .collapsed{ width:64px; .item{ position: relative; } .submenu{ position:absolute; top:0px; left:64px; z-index:99999; height:auto; display:none; } } } .menu-collapsed{ flex:0 0 64px; width: 64px; } .menu-expanded{ flex:0 0 230px; width: 230px; } </style>
利用次思想就可以形成一个简单的动态加载的例子