需求:根据登录的角色不一样,实现不同的路由展示,例如:超级管理员登录能访问所有菜单,普通用户登录就只能展示部分菜单。
1.首先在路由里面配置两份路由,一份静态的默认路由,例如登录页面,404页面
export const constantRoutes = [ { path: '/', redirect:'/login' }, { path: '/login', component: () => import('@/view/login') }, { path: '/404', component: () => import('@/view/404') }, { path: '/main', name:'main', component: () => import('@/view/main'), children: [{ path: 'home', component: () => import('@/view/asyncPage/home') }] } ]
然后在配置一份动态的路由,每个路由添加上roles属性,表明该路由那些角色能够访问
export const asyncRoutes = [{ path: 'xtgl', id:"2", icon:"el-icon-s-tools", toPath:'/main/xtgl', component: () => import('@/view/asyncPage/系统管理'), meta: { title: '系统管理', roles: ['admin', 'vip'] }, children: [{ path: 'jsgl', id:"2-1", toPath:'/main/xtgl/jsgl', component: () => import('@/view/asyncPage/角色管理'), meta: { title: '角色管理', roles: ['admin', 'vip'] }, }, { path: 'zhgl', id:"2-2", toPath:'/main/xtgl/zhgl', component: () => import('@/view/asyncPage/账号管理'), meta: { title: '账号管理', roles: ['admin'] }, }] }, { path: 'ddgl', id:"3", toPath:'/main/ddgl', component: () => import('@/view/asyncPage/订单管理'), meta: { title: '订单管理', roles: ['admin', 'vip'] }, children: [{ path: 'ddfh', id:"3-2", toPath:'/main/ddgl/ddfh', component: () => import('@/view/asyncPage/订单发货'), meta: { title: '订单发货', roles: ['admin', 'vip'] }, }, { path: 'ddlb', id:"3-1", toPath:'/main/ddgl/ddlb', component: () => import('@/view/asyncPage/订单列表'), meta: { title: '订单列表', roles: ['admin'] }, }, { path: 'wddd', id:"3-3", toPath:'/main/ddgl/wddd', component: () => import('@/view/asyncPage/我的订单'), meta: { title: '我的订单', roles: ['admin','vip'] }, children: [{ path: 'qbdd', id:"3-3-1", toPath:'/main/ddgl/wddd/qbdd', component: () => import('@/view/asyncPage/全部订单'), meta: { title: '全部订单', roles: ['admin'] }, }, { path: 'wcdd', id:"3-3-2", toPath:'/main/ddgl/wddd/wcdd', component: () => import('@/view/asyncPage/完成订单'), meta: { title: '完成订单', roles: ['admin', 'vip'] }, } ] }, ] }, { path: 'xxgl', id:"4", toPath:'/main/xxgl', redirect:'/main/xxgl/thgl', // component: (resolve) => require(['@/view/asyncPage/学校管理'], resolve),//映射的组件 component: () => import('@/view/asyncPage/学校管理'), meta: { title: '学校管理', roles: ['admin', 'vip'] }, children: [{ path: 'thgl', id:"4-1", toPath:'/main/xxgl/thgl', component: () => import('@/view/asyncPage/教师管理'), meta: { title: '教师管理', roles: ['admin', 'vip'] }, }, { path: 'xsgl', id:"4-2", toPath:'/main/xxgl/xsgl', component: () => import('@/view/asyncPage/学生管理'), meta: { title: '学生管理', roles: ['admin'] }, }, { path: 'jzgl', id:"4-3", toPath:'/main/xxgl/jzgl', component: () => import('@/view/asyncPage/家长管理'), meta: { title: '家长管理', roles: ['admin'] }, } ] },{ path: 'sz', id:"5", toPath:'/main/sz', component: () => import('@/view/asyncPage/设置'), meta: { title: '设置', roles: ['admin', 'vip','user'] } }]
2.然后封装一个函数,用来从动态路由中过滤当前角色能够访问的路由
function hasPermission(roles, route) { //判断角色是否有该路由的权限 if (route.meta && route.meta.roles) { return route.meta.roles.includes(roles) } else { return true } } function filterAsyncRoutes(asyncRoutes, roles) { let r = []; asyncRoutes.map((item) => { const tmp = { ...item }; if (hasPermission(roles, tmp) && !tmp.children) { r.push(tmp) } else if (hasPermission(roles, tmp) && tmp.children) { r.push({ path: tmp.path, id: tmp.id, component: tmp.component, meta: tmp.meta, toPath:tmp.toPath, children: filterAsyncRoutes(tmp.children, roles) }) } }) // 返回角色拥有的权限路由 return r; } export default filterAsyncRoutes;
3.登录的时候更具后台返回的角色(我这里使用mock 模拟后台返回的数据,只定义了3种角色,admin vip 和user),调用刚封装的函数,获取到该角色拥有权限的路由,调用addRoute动态注册该路由,并把路由存到
sessionStorage里面方面后面使用组件渲染。
login(){ // 登录前预校验 this.$refs.loginFromRef.validate(res=>{ if(res){ this.axios.post('/login',this.loginFrom).then(res=>{ let {data:{data}} = res; let userInfo = data.userInfo; window.sessionStorage.setItem('token',userInfo.token); window.sessionStorage.setItem('identity',userInfo.identity); this.$store.commit('loginIn',userInfo) let ro = JSON.stringify(filterAsyncRoutes(asyncRoutes, userInfo.identity)) console.log("登录重新注册路由",ro); window.sessionStorage.setItem('router', ro); resetRouter() filterAsyncRoutes(asyncRoutes, userInfo.identity).forEach(item => { router.addRoute('main', item) }) //路由添加完成后在动态添加404 ,解决刷新后页面跳404 和路由找不到的时候跳404 router.addRoute({ path: '*', redirect: '/404' }) this.$router.push('main/home'); }).catch(err=>{ console.log(err); }) }else{ return; } }) },
4,登录后如果刷新页面,路由会失效,所有在路由守卫里面在添加一次动态路由注册,解决该问题
let oneRun = true; //防止路由死循环 router.beforeEach((to, from, next) => { let roles = window.sessionStorage.getItem('identity'); if (to.path == '/login') { return next() } else { let token = window.sessionStorage.getItem('token'); token ? next() : next('/login') } // 每次跳转前存入要跳转的路径当成当前选中项的id window.sessionStorage.setItem('currIndex',to.path); if(_this){ _this.$store.commit('setCurrIndex',to.path); console.log( _this.$store.state.currIndex); } if(oneRun){ oneRun=false; console.log(asyncRoutes,roles); window.sessionStorage.setItem('router', JSON.stringify(filterAsyncRoutes(asyncRoutes, roles))); console.log("路由守卫重新注册路由"); filterAsyncRoutes(asyncRoutes, roles).forEach(item => { router.addRoute('main', item) }) //路由添加完成后在动态添加404 ,解决刷新后页面跳404 和路由找不到的时候跳404 router.addRoute({ path: '*', redirect: '/404' }) next({...to,replace:true}) } })
大体的思路就是这样的,源码传到了码云上,给大佬奉上仓库地址:https://gitee.com/wbw1993/vue-dynamic-routing
效果图:登录的用户名是admin能访问所有的菜单,vip只能展示部分菜单,其他用户名都只能看到首页和设置两个菜单
结语:代码未经优化,欢迎各位大佬指出不足的地方
路漫漫其修远兮...