vue - VueRouter 动态路由的实现
VueRouter定义路由参数定义方法请求路由数据引入模块最最最主要的还是全局路由导航守卫beforeEach 全局前置守卫router 模块VueRoter 版本问题router.addRoutes已废弃:使用 router.addRoute() 代替。router.addRoute添加一条新路由规则。如果该路由规则有 name,并且已经存在一个与之相同的名字,则会新版的 router 与3.0
·
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);
};
更多推荐
已为社区贡献6条内容
所有评论(0)