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

本文详细介绍了如何通过前后端配合,利用返回的菜单数据动态配置Vue Router,包括创建基础路由器、登录后动态添加路由、配置路由拦截和菜单管理。关键步骤包括处理后台返回的菜单结构,确保路由的动态加载和权限控制。
摘要由CSDN通过智能技术生成

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

第四步: 配置好菜单

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值