在Vue3中使用动态路由

3,316 阅读2分钟

第一步

区分路由表

需要到动态路由的场景一般都是在切换身份权限,所以我们需要将功能路由页面与权限页面区分开来,那么我们就会得到两个路由表

    export const routes = [
    {
        //调试环境
        path: '/',
        redirect: '/login'
    },
    {
        path: '/login',
        name: 'login',
        component: () => import('@/views/login.vue'),
    },
    {
        path: '/error',
        name: 'error',
        component: () => import('@/views/error/error.vue'),

    }, {
        path: '/main',
        name: 'main',
        redirect: '/main/dashboard',
        component: () => import('@/views/main.vue'),
        meta: {
            roles: ['0']
        },
        children: [
            {
                path: 'dashboard',
                name: 'dashboard',
                component: () => import('@/views/dashboard/dashboard.vue'),

            }
        ]
    }


]
export const RoleRoutes = [
    {
        path: 'order',
        name: 'order',
        component: () => import('@/views/order/order.vue'),
        meta: {
            roles: ['0']
        }
    },
    {
        path: 'user',
        name: 'user',
        component: () => import('@/views/user/user.vue'),
        meta: {
            roles: ['0']
        }
    }, {
        path: 'product',
        name: 'product',
        component: () => import('@/views/product/product.vue'),
        meta: {
            roles: ['0']
        }
    }
]

第一个路由表是公共路由表,不涉及到身份权限判断,第二个路由表我们根据meta配置roles来判断该路由所需要的身份权限

第二步

使用Pinia保存当前用户的身份

state: () => {
    return {
        role:localStorage.getItem('role') ? localStorage.getItem('role') : null,
    }
},

在我们用户登录时,我们需要将用户的身份存入Pinia中

第三步

在全局路由守卫中对用户身份进行判断,并动态添加路由

判断访问页面所需权限

我们使用filterAsyncRoutes方法将RoleRoutes路由表作为第一个参数传入,将当前的用户身份roles作为第二个参数传入,用forEach循环以及解构赋值并使用hasPermission函数判断哪些页面的权限符合当前用户的身份,将符合条件的页面pushres数组中。

filterAsyncRoutes函数:

    /**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes: any, roles: any) {
    const res:any = []

    routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
            res.push(tmp)
        }
    })

    return res
}

hasPermission函数:

function hasPermission(role: string, route: any) {
    if (route.meta && route.meta.roles) {
        return route.meta.roles.includes(role)
    } else {
        return true
    }
}

动态添加路由

为了应付用户刷新,路由失效的问题,我们需要定义一个自定义标识registerRouteFresh,初始化为true,在首次加载时,让页面路由动态添加至路由表中,在下次跳转路由后不执行addRoute;在用户刷新页面时,registerRouteFresh被初始化为true,重新进行路由动态加载,路由动态加载完成后registerRouteFresh置为false不再重复添加

    let registerRouteFresh = true // 定义标识,记录路由是否添加
    
    router.beforeEach((to, from, next) => {
    const userStore = useUserStore()
    const roleStore = useRoleStore()
    // 判断有没有登录
    if (!userStore.token) {
        //如果没登录,但是去得页面是login页
        if (to.name == "login") {
            next();
        } else {
            message.error('请先完成登录!')
            router.push('/login')
        }
    } else {
        //如果登录了
        //首次登录跳转动态添加路由状态是true
        if (registerRouteFresh) {
            if (!userStore.role) {
                userStore.GET_ROLE()
            }
            const role = userStore.role || localStorage.getItem('role')
            
            const addRouter = filterAsyncRoutes(RoleRoutes, role)
            addRouter.forEach((v: any) => {
                router.addRoute('main', v)
            })
            next({ ...to, replace: true })
            registerRouteFresh = false
        } else {
            next()

        }
    }
});

结束

最近一段时间学习完Vue3将毕设的后台独立分离出来使用Vue3+Vite+Pinia+TypeScript重构了一下,这篇文章作为一个记录,下一篇文章应该就是用React将这个项目再次重构了