Vue Router beforeEach导航守卫获取Store权限数据为空问题
问题根因
出现这个现象的核心原因有三点:
- 时序错位:你把权限加载逻辑写在了NavBar组件的
created钩子中,而路由beforeEach守卫的执行时机早于组件生命周期的created钩子,守卫触发时权限接口的请求甚至还没发出,此时读取Store拿到的自然是空数组。 - 代码逻辑错误:你在守卫中写了
await store.getters.availableAppPermissions,但Vuex的getter是同步返回值的,不是Promise对象,await一个普通值完全不会等待接口请求完成,起不到阻塞等待加载的作用。 - 控制台显示差异:你观察到的console打印数组长度为0、Vue DevTools中数组长度为1,是console打印引用类型的惰性求值特性导致的:打印语句执行瞬间数组确实是空的(长度0),等你手动在控制台展开数组查看时,接口请求已经完成、Store状态已经更新,你看到的是更新后的值(长度1),不是Store读取异常。
修复方案
要保证导航守卫执行时权限数据一定加载完成,核心是把权限加载的触发时机从组件生命周期挪到全局路由守卫流程中,不要依赖组件挂载触发加载,具体修改步骤如下:
1. 给Store模块增加加载完成标记,避免重复请求
修改原有Store模块,新增加载状态位,已经加载过权限就直接返回,不重复发起接口请求:
import axios from 'axios' export default { state: { availableApps: [], permissionsLoaded: false // 新增:标记权限数据是否已加载完成 }, mutations: { SET_AVAILABLE_APPS(state, availableApps) { state.availableApps = availableApps state.permissionsLoaded = true // 数据写入完成后标记为已加载 }, // 登出时可调用这个mutation重置状态 RESET_PERMISSIONS(state) { state.availableApps = [] state.permissionsLoaded = false } }, actions: { loadAppsAvailableForCurrentUser({ commit, state }) { // 已加载过直接返回成功Promise,不重复请求 if (state.permissionsLoaded) return Promise.resolve() return axios.get('/v1/apps').then(data => { const filteredApps = data.data.filter(app => app.showInMenu) commit('SET_AVAILABLE_APPS', filteredApps) }) } }, getters: { availableApps(state) { return state.availableApps }, availableAppPermissions(state) { return state.availableApps.filter(item => item.hasPermission == false) } } }
2. 改造全局前置守卫,前置加载权限
把权限加载逻辑放到路由守卫中,已登录状态下先等待权限加载完成,再做权限校验,同时修正原有逻辑中多次调用next的问题:
router.beforeEach(async (to, from, next) => { // 已登录状态下先确保权限数据加载完成 if (store.getters.loggedIn) { await store.dispatch('loadAppsAvailableForCurrentUser') } // 权限加载完成后再做校验 const deniedPermissions = store.getters.availableAppPermissions const needCheckPermission = to.matched.some(record => record.meta.requiresPermission) const isNoPermission = deniedPermissions.some(item => to.path.includes(item.appUrl)) if (needCheckPermission && isNoPermission) { return next({ name: 'Home' }) } next() })
3. 清理组件中的冗余调用
删除NavBar组件created钩子中this.$store.dispatch('loadAppsAvailableForCurrentUser')这行代码,权限加载统一由路由守卫负责,从根源上避免时序问题。
注意:用户登出时记得调用
RESET_PERMISSIONSmutation重置权限状态,避免切换账号时出现权限数据串用的问题。
内容的提问来源于stack exchange,提问作者spinnning
相关产品推荐
相关产品推荐

