vue - VueRouter 动态路由的实现

最近在写一个新项目,前端使用动态路由实现页面权限管控

定义路由参数

先定义一下需要后台传的路由参数(数据是自己mock的一个路由数据)

{
  "router": [
    {
      "path": "/ProductDynamic",
      "component": "Layout",
      "redirect": "/ProductDynamic/TypeMachineQualityAnalys",
      "name": "ProductDynamic",
      "meta": {
        "title": "父菜单一",
        "icon": "el-icon-menu"
      },
      "children": [
        {
          "path": "TypeMachineQualityAnalys",
          "name": "TypeMachineQualityAnalys",
          "component": "ProductDynamic/TypeMachineQualityAnalys",
          "meta": {
            "title": "子菜单一"
          }
        },
        {
          "path": "TypeMachineCapacityAnalys",
          "name": "TypeMachineCapacityAnalys",
          "component": "ProductDynamic/TypeMachineCapacityAnalys",
          "meta": {
            "title": "子菜单二"
          }
        }
      ]
    },
   ]
  }

定义方法请求路由数据

引入模块
import Layout from '@/layout';
const _import = require('./modules/_import_' + process.env.NODE_ENV); //获取组件的方法
/**
 * 處理路由json數據,轉換為前端路由需要的路由格式
 *
 * @param {*} asyncRouterMap 後臺的路由數據
 * @return {*}
 */
function filterAsyncRouter(asyncRouterMap) {
  //遍历后台传来的路由字符串,转换为组件对象
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') {
        //Layout组件特殊处理
        route.component = Layout; //引入组件
      } else {
        route.component = _import(route.component);
      }
    }
    if (route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children);
    }
    return true;
  });
  return accessedRouters;
}
// 獲取系統菜單
export const asyncRoutes = () => {
  return new Promise(resolve => {
    GetSysMenuTree().then(async res => {
      let result = res.data.router;
      const sysRoutes = filterAsyncRouter(result);
      resolve(sysRoutes);
    });
  });
};

最最最主要的还是全局路由导航守卫

beforeEach 全局前置守卫

路由导航这还存在在一些问题,后期会着手进行解决
因为考虑到了用户可能会在登录后F5刷新以及退出登录等等的情况
故使用了两个变量作判断
本地存路由数据还需改进…(仅供参考)
(有更好的解决方法,欢迎指教)

router.beforeEach(async (to, from, next) => {
  // console.log("reouter1",router);
  // console.log('reouter2', router.getRoutes());
  NProgress.start();
  // 设置页面标题
  document.title = getPageTitle(to.meta.title);
  const hasToken = getToken();
  const userid = store.getters.userid;
  const isAddAsyncMenuRouter = store.getters.isAddAsyncMenuRouter; // 判斷是否初次登陸
  if (hasToken && userid) {
    if (isResetAsyncMenuRouter && isAddAsyncMenuRouter) {
      next({ replace: true });
      NProgress.done();
    } else {
      try {
        const accessRoutes = await asyncRoutes(); //獲取動態路由
        store.commit('user/SET_ROUTES', accessRoutes);
        // router.addRoutes(accessRoutes); //
        /**  */
        await accessRoutes.forEach(element => {
          // console.log(element)
          router.addRoute(element);
        });

        isResetAsyncMenuRouter = true;
        store.commit('user/SET_ISADDASYNCMENUROUTER', true);//判断是否是退出按钮触发退出
        // 设置replace: true,这样导航将不会留下历史记录
        next({ ...to, replace: true });
      } catch (error) {}
    }
  } else {
    if (['/login'].indexOf(to.path) !== -1) {
      next({ replace: true });
    } else {
      // 其他没有访问权限的页面被重定向到登录页面
      next(`/login?redirect=${to.path}`);
      NProgress.done();
    }
  }
});

router 模块

定义两个js 文件
在这里插入图片描述

作用: 导出的实际格式为{default:组件名},require不支持默认导入,所以加载组件需要require().default

_import_development
module.exports = file => require('@/views/' + file + '/index.vue').default; // vue-loader
_import_production
module.exports = file => () => import('@/views/' + file + '/index.vue');

VueRoter 版本问题

router.addRoutes 已废弃:使用 router.addRoute() 代替。
router.addRoute 添加一条新路由规则。如果该路由规则有 name,并且已经存在一个与之相同的名字,则会

既然官网在新版的router 就废弃了,那我就直接使用了新版
但是 新版的 router.addRoutes 还是可以使用的 ,至于为啥,这就没有过多的去了解了
(希望有大佬教一教)

新版的 router 与3.0版本的 的matcher 多了一些方法

在这里插入图片描述

router.getRoutes();  可以获取得到所有的路由参数

(
但出现了一个疑问,因为我在前端定义了4个静态路由,其他路由都是后台获取。
而我在获取路由的时候打印的router 下的 options.routes  只显示的是静态路由
看不到动态获取的路由,目前为止,为找出被放在了哪里
router.getRoutes();  方法能获取到静态和动态的所有路由

这就很疑惑了
)

在这里插入图片描述

所遇到的问题

在这里插入图片描述

这里通过导航保护重定向的一个问题

*问题的原因:

  • vue-router路由版本更新产生的问题,导致路由跳转失败抛出该错误;
  • 真正的原因是由于返回了一个Promise对象, 正常的跳转由then方法执行 当正常的路由跳转, 被"路由导航守卫"拦截并重新指定路由时,
  • 由于 this.$router.push() 返回的是Promise对象, 此时then方法不能正常执行, 无法跳转到指定路由, 就触发了该对象的捕获错误的方法,
  • throw抛出错误, 但并不影响程序功能

解决:

/**
 * 方法一: 降低 vue-router 版本
 * 更换vue-router版本为: npm i vue-router@3.0.7 -S
 */

/**
 * 方法二:
 * 通过重写VueRouter原型对象上的push方法, 覆盖原来抛出异常的方法, "吞掉"异常
 *
 */
const originalPush = Router.prototype.push;
Router.prototype.push = function push(location, onResolve, onReject) {
  // 判断用户有没有传后面两个可选参数
  if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject);
  /* 
      默认底层: catch()方法代码  throw err : 抛出异常
      吞掉报错原理: 重写catch()方法,把默认底层的 throw err给去掉,就不会抛出异常
      */
  return originalPush.call(this, location).catch(err => err);
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值