MST

星途 面试题库

面试题:Vue中Vuex与Router结合实现复杂路由状态管理

在一个多视图嵌套且具有权限控制的Vue应用中,路由状态不仅要管理页面数据,还要根据用户权限动态生成路由菜单。例如,普通用户和管理员用户看到的路由菜单不同,且路由切换时要保证相关页面状态的正确传递和保存。请阐述如何基于Vuex和Router设计架构来满足这些需求,包括如何利用Vuex的模块化、命名空间等特性,以及Router的导航守卫等功能。
22.5万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

1. Vuex相关设计

1.1 模块化

  • 用户权限模块
    • 创建一个userPermission模块,用于存储用户权限相关信息,例如userRole(用户角色,如'admin''user')。
    • 在该模块的state中定义权限相关状态:
const userPermission = {
  namespaced: true,
  state: () => ({
    userRole: null
  }),
  mutations: {
    SET_USER_ROLE(state, role) {
      state.userRole = role;
    }
  },
  actions: {
    async fetchUserRole({ commit }) {
      // 假设从后端获取用户角色
      const response = await axios.get('/api/user/role');
      commit('SET_USER_ROLE', response.data.role);
    }
  }
};
  • 路由菜单模块
    • 创建routeMenu模块,用于生成和管理路由菜单。
    • state中存储动态生成的路由菜单:
const routeMenu = {
  namespaced: true,
  state: () => ({
    menus: []
  }),
  mutations: {
    SET_ROUTE_MENUS(state, menus) {
      state.menus = menus;
    }
  },
  actions: {
    generateRouteMenus({ commit, rootState }) {
      const { userRole } = rootState.userPermission;
      let menus = [];
      if (userRole === 'admin') {
        menus = [
          { path: '/admin/dashboard', name: 'Admin Dashboard' },
          { path: '/admin/users', name: 'Manage Users' }
        ];
      } else {
        menus = [
          { path: '/user/dashboard', name: 'User Dashboard' }
        ];
      }
      commit('SET_ROUTE_MENUS', menus);
    }
  }
};

1.2 命名空间

  • 为每个模块设置namespaced: true,确保模块内的状态、mutations、actions等不会与其他模块冲突。例如,在userPermission模块中,通过userPermission/SET_USER_ROLE这样的命名空间来提交mutation,在组件中调用this.$store.commit('userPermission/SET_USER_ROLE', 'admin')

2. Router相关设计

2.1 导航守卫

  • 全局前置守卫
    • router.js中设置全局前置守卫,用于在路由切换前检查用户权限并确保相关页面状态的正确传递和保存。
import router from './router';
import store from './store';

router.beforeEach(async (to, from, next) => {
  // 确保用户角色已获取
  if (!store.state.userPermission.userRole) {
    await store.dispatch('userPermission/fetchUserRole');
  }
  const { userRole } = store.state.userPermission;
  const routeMenus = store.state.routeMenu.menus;
  const hasPermission = routeMenus.some(menu => menu.path === to.path);
  if (hasPermission) {
    // 保存当前页面状态(假设使用keep - alive,可在组件内通过activated和deactivated钩子保存和恢复状态)
    if (from.name) {
      // 可在此处将from页面状态保存到Vuex
    }
    next();
  } else {
    next('/403'); // 无权限时跳转到403页面
  }
});
  • 组件内守卫
    • 在需要特殊权限控制的组件内设置守卫,例如在AdminDashboard.vue组件中:
export default {
  beforeRouteEnter(to, from, next) {
    const { userRole } = this.$store.state.userPermission;
    if (userRole === 'admin') {
      next();
    } else {
      next('/403');
    }
  }
};

3. 整合Vuex和Router

  • main.js中,先初始化Vuex,然后在Router设置完成后挂载Vue实例。
import Vue from 'vue';
import store from './store';
import router from './router';

new Vue({
  store,
  router,
  render: h => h(App)
}).$mount('#app');
  • 在组件中,通过this.$store访问Vuex状态和触发actions,通过this.$router进行路由导航操作。例如,在App.vue中可以通过this.$store.dispatch('routeMenu/generateRouteMenus')生成路由菜单,并在模板中展示动态路由菜单。