vue2.0后台管理 动态加载菜单
最近接手一个后台管理项目,需要实现从后台拉取导航菜单的效果;根据不同的登录用户的权限分别拉取不同的导航菜单,进行页面的跳转
实现方法:
从后台返回菜单与动态路由的数组做匹配,选择需要动态加载的路由,在将后台返回的菜单加载到页面即可
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>
利用次思想就可以形成一个简单的动态加载的例子