vue-router addRoutes后如何刷新?

从后台读取角色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("/");
            }
阅读 18.6k
1 个回答
推荐问题
宣传栏