在Vue Router中结合Pinia实现角色路由及初始化错误解决
解决Pinia未初始化时加载角色路由的问题
核心问题是Router初始化流程早于Pinia激活,直接在createRouter时调用useAuthStore会导致Pinia未激活的错误。下面是两种可行的解决方案:
方案一:先初始化基础路由,后动态添加角色路由
这种方式适合不同角色有完全独立路由结构的场景,步骤如下:
1. 定义基础路由与角色路由映射
// router/index.js import { createRouter, createWebHistory } from 'vue-router' // 无需权限的基础路由(如登录页) const baseRoutes = [ { path: '/login', name: 'login', component: () => import('@/pages/Login') } ] // 各角色对应的路由集合 export const roleRoutesMap = { roleOne: [ { path: '/home', name: 'home', component: () => import('@/pages/RoleOne/Home'), }, // roleOne其他路由... ], roleTwo: [ { path: '/home', name: 'home', component: () => import('@/pages/RoleTwo/Home'), }, // roleTwo其他路由... ], roleThree: [ // roleThree其他路由... ] } // 先创建仅包含基础路由的Router实例 export const router = createRouter({ history: createWebHistory(), routes: baseRoutes })
2. 在Pinia初始化后加载角色路由
在main.js中,先激活Pinia,再根据用户角色动态添加路由:
// main.js import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' import { router, roleRoutesMap } from './router' import { useAuthStore } from '@/stores/auth' const app = createApp(App) const pinia = createPinia() // 先挂载Pinia和Router app.use(pinia) app.use(router) // 初始化角色路由 const initRoleRoutes = async () => { const authStore = useAuthStore() // 优先从Pinia取角色,无则从本地存储/后端接口获取 if (!authStore.user.role) { await authStore.fetchCurrentUser() // 假设此方法从后端拉取用户信息并更新Pinia } // 添加对应角色的路由 const targetRoutes = roleRoutesMap[authStore.user.role] || [] targetRoutes.forEach(route => router.addRoute(route)) // 已登录状态下,若当前在登录页则跳转到首页 if (authStore.user.role && router.currentRoute.value.path === '/login') { router.push('/home') } } // 执行路由初始化后再挂载App initRoleRoutes().then(() => { app.mount('#app') })
3. 导航守卫处理页面刷新场景
页面刷新后动态路由会丢失,添加全局前置守卫补全路由:
// router/index.js import { useAuthStore } from '@/stores/auth' router.beforeEach(async (to, from, next) => { const authStore = useAuthStore() const isLoggedIn = !!authStore.user.role // 已登录用户访问登录页,直接跳首页 if (to.path === '/login' && isLoggedIn) { next('/home') return } // 未登录用户访问权限页,跳登录页 if (!isLoggedIn && to.path !== '/login') { next('/login') return } // 刷新后路由丢失,重新加载对应角色路由 if (isLoggedIn && !router.hasRoute(to.name)) { const targetRoutes = roleRoutesMap[authStore.user.role] || [] targetRoutes.forEach(route => router.addRoute(route)) // 重新跳转当前路由,确保路由已生效 next({ ...to, replace: true }) } else { next() } })
方案二:路由内动态加载组件(适合单路由组件切换场景)
如果只是部分页面组件随角色变化,而非整个路由结构不同,可以直接在路由定义中动态返回组件:
// router/index.js import { createRouter, createWebHistory } from 'vue-router' import { useAuthStore } from '@/stores/auth' const router = createRouter({ history: createWebHistory(), routes: [ { path: '/login', name: 'login', component: () => import('@/pages/Login') }, { path: '/home', name: 'home', // 组件加载时再获取角色,此时Pinia已激活 component: async () => { const { user } = useAuthStore() switch(user.role) { case 'roleOne': return import('@/pages/RoleOne/Home') case 'roleTwo': return import('@/pages/RoleTwo/Home') case 'roleThree': return import('@/pages/RoleThree/Home') default: return import('@/pages/DefaultHome') } } } // 其他通用路由... ] })
内容的提问来源于stack exchange,提问作者Karna
相关产品推荐
相关产品推荐

