从后台读取角色menus对象,采用addRoutes方式增加路由,登出后换用户登录继续addRoutes路由如果存在重复的会报
vue-router.common.js?1ecf:18 [vue-router] Duplicate named routes definition: { name: "top-menu", path: "" }
并且报错(据观察是router不存在跳转不到)
TypeError: Cannot read property 'beforeRouteEnter' of undefined
如果刷新页面,这两个错误都不会
手摸手解决方案是 location.reload()登出重新加载页面(重新加载页面用户体验不好,目前是直接跳转的)
logout() {
this.$store.dispatch('LogOut').then(() => {
location.reload()// 为了重新实例化vue-router对象 避免bug
})
}
我的代码如下(多粘点对做权限的同学有参考意义)
main.js
// 不重定向白名单
const whiteList = ['/login', ];
router.beforeEach((to, from, next) => {
let url = to.path;
if (sessionStorage.getItem("tokenList")) {
const menus = JSON.parse(sessionStorage.getItem('menus'));
// 路由是否加载完成标识
if(!store.getters.routerLoadDone){
if (menus && menus.length > 0) {
store.dispatch('GenerateRoutes', { menus }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to }) // hack方法 确保addRoutes已完成
})
}
}
if (url === "" || url === "/" || url === "/login") {
if(menus && menus.length >0){
let indexMenu;
for (let menu of menus) {
indexMenu = menu.children.filter((child, i) => {
return child.is_index === 1;
});
if (indexMenu && indexMenu.length > 0) break;
}
if (indexMenu && indexMenu.length > 0) {
next(indexMenu[0].path);
}else{
next(menus[0].children[0].path);
}
}else{
next('404');
}
}
else {
next();
}
}
else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next('/login') // 否则全部重定向到登录页
}
}
});
store/modules/router.js
/**
* menus转换为route
* @param menus
* @returns {Array}
*/
function convertRouteMap(menus) {
let routers = [];
if (menus) {
for (let menu of menus) {
let url = menu.url;
let contextPath = url.substr(0, url.indexOf("/"));
let req = url.substr(url.indexOf("/") + 1);
const componentVal = resolve => {
if (contextPath === 'views') {
require(['views/' + req], resolve)
} else if (contextPath === 'packages') {
require(['packages/' + req], resolve)
}
};
let route = {path: menu.path, component: componentVal, name: menu.name};
if (menu.children) {
route.children = convertRouteMap(menu.children);
}
if (menu.redirect) {
route.redirect = menu.redirect;
}
routers.push(route);
}
}
return routers;
}
const routers = {
state: {
routers: constantRoutes,
addRouters: [],
routerLoadDone: false,
},
mutations: {
SET_ROUTERLOADDONE: (state, routerLoadDone) => {
state.routerLoadDone = routerLoadDone;
state.routers = constantRoutes;
state.addRouters = [];
},
SET_ROUTERS: (state, routers) => {
state.addRouters = routers;
state.routers = constantRoutes.concat(routers);
// 404 页 '*' 放在所有route之后
let notFound = {path: '*', component: r => require(['views/not-found'], r), name: 'not-found'};
state.addRouters.push(notFound);
state.routers.push(notFound);
state.routerLoadDone = true;
}
},
actions: {
GenerateRoutes({commit}, data) {
return new Promise(resolve => {
const {menus} = data;
let topMenu = [{path: '/', component: r => require(['views/menu/top-menu'], r), name: 'top-menu'}];
let children = [];
for (let menu of menus) {
if (menu.children) {
for (let child of menu.children) {
children.push(child);
}
}
}
topMenu[0].children = convertRouteMap(children);
commit('SET_ROUTERS', topMenu);
resolve()
})
}
}
};
routes/index.js
/**
* 定义路由
* @param r
* @constructor
*/
import Router from 'vue-router'
import Vue from 'vue';
Vue.use(Router)
const Test = r => require(['views/test/test'], r);
const CommonComp = r => require(['views/test/commoncomp'], r);
const Login = r => require(['views/login'], r);
// 页面路由
export const constantRoutes = [
{path: '/login', component: Login, name: 'login'},
{path: '/test', component: Test, name: 'test'},
{path: '/commoncomp', component: CommonComp, name: 'commoncomp'},
];
// 创建一个路由对象用于管理页面的路由
// 创建的 router 对象中,如果不配置 mode,就会使用默认的 hash 模式,该模式下会将路径格式化为 #! 开头
// 添加 mode: 'history' 之后将使用 HTML5 history 模式,该模式下没有 # 前缀,而且可以使用 pushState 和 replaceState 来管理记录。
export default new Router({
// mode: 'history',
routes: constantRoutes
});
登出代码
logout() {
sessionStorage.clear();
this.$store.commit('SET_ROUTERLOADDONE', false);
this.$router.push("/");
}
vue 解决addRoutes动态添加路由后,刷新失效问题
https://segmentfault.com/a/11...