背景: 不同角色展示不同菜单,不同菜单对应的路由实现动态加载。即不在router.js去配置菜单对应的路由,二根据后台返回的菜单路径动态配置组件及其他信息。
备注:此文很长,但都是干货
前提条件:
和后端约定好返回的菜单数据格式页面组件命名规范 (比如:功能名/ *** 作名/index.vue)无菜单的子页面、其他页面需自己手动配置 具体实现第一步: 创建基础版router (在项目router文件夹下建index.js)
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const routes= [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true,
meta: { title: '登录', icon: '' }
},
// ....其他需要配置的页面
]
const router = new Router({
mode: 'history',
routes,
});
// 导出路由
export default router
第二步: 登录成功后,获取菜单动态添加路由
import Layout from '@/layout'
import router from '@/router'
// menusArr 后台返回的menu
addRouter ( menusArr ) {
let routerArrList = []; // 声明一个空的数组,储存菜单对应的路由
if(menusArr == null || !menusArr ){ // 若为空、null则返回
return
}
for(let menu of menusArr){ // 循环菜单
// 一级菜单
let outMenu = {
path: menu.path,
component: Layout,
alwaysShow: true,
redirect: (menu.children && menu.children.length>0) ? menu.children[0].path : menu.path, // 若有子类,默认显示子类第一个
meta: { title: menu.name, icon: menu.icon ? menu.icon : 'iconicon-bid-archive' },
children:[]
};
// 二级菜单
const getChildRoute = (childArr,obj) => {
for(let cR of childArr){
let address = cR.path+'/index';
if(cR.path.indexOf('/') <= -1){
address = '/'+cR.path+'/index'
} // 动态配置对应的页面组件路径
let inMenu = {
path: cR.path,
name: cR.name,
component: () => Promise.resolve().then(()=>require(`@/views${address}`)),
meta: { title: cR.name },
children:[]
}
if(cR.children && cR.children.length>0) {
inMenu = {
...inMenu,
redirect: cR.children[0].path,
}
}
obj.children.push(inMenu);
if(cR.children && cR.children.length>0){
getChildRoute(cR.children,inMenu)
}
}
};
if(menu.children && menu.children.length>0){
getChildRoute(menu.children,outMenu)
}else {
let address = menu.path+'/index';
if(menu.path.indexOf('/') <= -1){
address = '/'+menu.path+'/index'
}
outMenu.children.push(
{
path: menu.path,
name: menu.name,
component: () => Promise.resolve().then(()=>require(`@/views${address}`)),
meta: { title: menu.name, icon: 'icongongzuotai' }
},
)
}
routerArrList.push(outMenu)
}
router.addRoutes(routerArrList); // 添加菜单路由
}
后台返回的menu数据格式如下
[{
icon: "iconicon-bid-archive"
id: "f986f846d8c7a6b5964c3c916ff1c7d8"
name: "系统管理"
parentId: "root"
path: "/system"
children:[
{icon: null,id: "d7df45f07e4dadd39b9879a686cbd895",name: "菜单管理",parentId: "adb0b32ee09a816919d858dd61f3f3dc",path: "/setting_manage/menu"}
]
},
//.........
]
第三步: 配置路由拦截(新建一个permission.js)
import router from './router'
import { getToken} from '@/utils/auth' // 校验是否有token
const whiteList = ['/login'] // 无需登录的白名单列表
// 路由跳转前,判断token
router.beforeEach(async (to, from, next) => {
document.title = getPageTitle(to.meta.title)// 设置页面title
const hasToken = getToken()// 确认用户是否已经登录
if (hasToken) {
next()
} else { // 无token
if (whiteList.indexOf(to.path) !== -1) { // 在免费登录的白名单中,则直接进入
next()
} else {
next(`/login?redirect=${to.path}`)// 其他页面无权限进入,则重定向到登录页面,login页面可获取redirect参数,便于登录后快速返回
}
}
})
//路由报错----必须添加,若出现后台返回不规范的path路径,写了此方法可避免页面报错或空白
router.onError((callback)=>{
router.push( {path:'/404/page'} )
});
第四步: 配置好菜单
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)