vue-router ------用addRoutes 实现动态权限路由加载

vue-router ------用addRoutes 实现动态权限路由加载,第1张

背景: 不同角色展示不同菜单,不同菜单对应的路由实现动态加载。即不在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'} )
});

第四步: 配置好菜单

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/940505.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存