vue动态添加的路由页面刷新时失效

7,439 阅读4分钟

artical image

问题描述

昨天在做vue后台管理系统有关权限页面动态添加到路由的功能时,遇到一个问题:动态添加的路由页面,在页面刷新时出现了404的情况。

场景

后台管理系统的权限控制是通过在前端页面定义权限code, 把code给后台同学保存配置到表中,之后根据后台返回的权限code列表与前端页面配置的code菜单列表做筛选匹配,code相等的页面就是有权限的页面,再通过router.addRoute()动态添加到路由中,有权限的路由才可以被访问,否则会提示无权限。

固定路由一开始就会放在new Router中,比如登录页面login

接口返回

api image

前端菜单定义

menu image

vuex中的方法

vuex image

addRoute image

出现的问题

登录后,通过调用vuex中的方法,完成获取权限code,动态筛选权限路由页面操作,然后通过router.addRoute()将有权限菜单添加到路由中,进入动态添加的路由页面,刷新页面出现404

原因分析

页面刷新时,路由重新初始化,动态添加的路由此时已不存在,只有一些固定路由(比如登录页面)还在,所以出现了404的情况

解决方案

VUEX store中存储的数据会在页面刷新时清空。 在路由的全局导航router.beforeEach处做个判断,根据VUEX中存放的list是否有值来判断页面是否是刷新,如果不为0,则是第一次登陆,登录后会走匹配路由的方法,不会有问题;如果list.length为0,就为刷新页面,需要重新执行路由匹配,重新添加动态路由即可。

实现代码 route/index.js的导航守卫中添加逻辑判断

---------router.js-------------

const constantRoutes = [
    {
        path: '/',
        redirect: '/login'
    },
    {
        path: '/login',
        name: 'login',
        meta: {
            auth: false
        },
        component: () => import('@/views/login')
    },
    {
        path: '/layout',
        name: 'layout',
        meta: {
            auth: true
        },
        component: () => import('@/views/layout/index'),
        children: [
            {
                path: '/index',
                name: 'index',
                component: () => import('@/views/home')
            }
        ]
    },
    {
        path: '*',
        component: () => import('@/views/error/404')
    }
]

Vue.use(VueRouter)
const createRouter = () =>
    new VueRouter({
        routes: constantRoutes
    })
export function resetRouter() {
    const newRouter = createRouter()
    router.matcher = newRouter.matcher // reset router
}
const router = createRouter()
 
//页面刷新后重新设置权限页面动态路由,防止出现动态路由404问题
const reSetPermissionList = to => {
    return new Promise((resolve, reject) => {
        if (to.path !== '/login' && store.state.permission.permissionList.length === 0) {
            store
                .dispatch('permission/getPermissionList')
                .then(() => {
                    resolve('permCode')
                })
                .catch(error => {
                    resolve('permCode')
                })
        } else {
            resolve()
        }
    })
}
router.beforeEach((to, from, next) => {
     
    const accessToken = localStorage.getItem('accessToken')
    if (_.isEmpty(accessToken)) {//是否已经登录 否 去登陆页面
        next({
            path: '/login',
            query: {
                redirect: to.fullPath
            }
        })
    } else { //已登录用户进入页面
        if (to.path === '/login') {
            next({ path: '/index' })
        } else {
             reSetPermissionList(to).then(data => {
                    data === 'permCode' ? next({ path: to.path, query: to.query }) : next()
                })
        }
    }
   
})

总结

主要通过在全局导航处判断VUEX中的数据是否存在,判断页面是否刷新,是的话重新走一遍权限路由匹配的方法。

结尾小彩蛋

第一次遇到这个问题,比较懵缺......一时找不到原因,后来通过查找,看到一篇文章,里面的情况跟我遇到的差不多,在此贴上链接,感谢这位网友的分享 ^3^ {% link 参考文章链接--前往 blog.csdn.net/qq_31906983… %}

2021年03月后记

存在一个问题奥~:利用路由的全局导航router.beforeEach拦截判断VUEX中的数据是否存在,以此作为页面是否刷新的依据固然好用,but....后面发现一个尴尬的问题,如果后台接口返回的权限本身就是空数组,那这个权限的请求就会出现死循环了....

按理说不会出现一个权限都木有的情况,好歹给个默认权限吧,但是我们这没权限就返回空。好吧,那也好说,既然都为空会出现逻辑冲突,那我就主动给list塞一个值吧,只要这个值不会对应前台的路由菜单就可以,用户也感知不到这个权限的存在,吆西~~~完美哈哈。。。

说了这么多,还是看代码吧:

    const actions = {
    // 获取权限数据
    async getPermissionList({ commit, state }, args = 'geting') {
        console.log('获取权限', state)
        return new Promise(async (resolve, reject) => {
            resetRouter()             
            const [res] = await myPermissionCodes({ clientId, orgCode: storage.get('orgCode') || '' })
            if (res) {
                //改动在这里 >>>>>>>> =============== ^-^ =================
                let list = res.list.length !== 0 ? res.list : ['testCode']//此处返回空数组时,前端给一个值即可
                commit('updatePermissionList', list)
                resolve(list)
            } else {
                //自动退出登录...
                storage.clear()
                router.replace('/login')
                reject()
            }
        })
    }
}

文章首次发表于我的个人博客。欢迎浏览嘻嘻