当前位置 博文首页 > #Empty:使用vue-element-admin框架从后端动态获取菜单

    #Empty:使用vue-element-admin框架从后端动态获取菜单

    作者:#Empty 时间:2021-04-28 18:14

    使用vue-element-admin框架从后端动态获取菜单

    1、前言

    ? vue-element-admin是一个纯前端的框架,左侧菜单是根据路由生成的。实际开发中经常需要根据当前登陆人员的信息从后端获取菜单进行展示,本文将详细介绍如何实现该功能。

    2、详解

    ? 整体思路为:登陆 > 成功后根据用户信息获取菜单 > 根据菜单生成路由信息

    2.1、新增asyncRoutes路由

    ? 在vue-router路径src\router\index.js中新增asyncRoutes数组,用来存放后端获取的菜单对应的路由信息。

    export const asyncRoutes = [
      { path: '*', redirect: '/404', hidden: true }
    ]
    

    image-20210428151858065

    constantRoutes和asyncRoutes的区别

    constantRoutes:不需要动态判断权限的路由,如登录页、404等通用页面。

    asyncRoutes:需求动态判断权限并通过addRoutes动态添加的页面

    2.2、新建permission.js文件

    ? 在vuex路径src\store\modules\permission.js下新建permission.js文件,该操作为最重要的一步,主要是从后端查询菜单并生成路由。

    import { asyncRoutes, constantRoutes } from '@/router'
    import { fetchUserMenuList } from '@/api/user'
    import Layout from '@/layout'
    
    /**
     * 静态路由懒加载
     * @param view  格式必须为 xxx/xxx 开头不要加斜杠
     * @returns 
     */
    export const loadView = (view) => {
      return (resolve) => require([`@/views/${view}.vue`], resolve)
    }
    
    /**
     * 把从后端查询的菜单数据拼装成路由格式的数据
     * @param routes
     * @param data 后端返回的菜单数据
     */
    export function generaMenu(routes, data) {
      data.forEach(item => {
        const menu = {
          path: item.url, 
          component: item.component === '#' ? Layout : loadView(item.component), 
          hidden: item.status === 0, // 状态为0的隐藏
          redirect: item.redirect,
          children: [],
          name: item.code,
          meta: item.meta
        }
    
        if (item.children) {
          generaMenu(menu.children, item.children)
        }
        routes.push(menu)
      })
      return routes
    }
    
    const state = {
      routes: [],
      addRoutes: []
    }
    
    const mutations = {
      SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        // 拼接静态路由和动态路由
        state.routes = constantRoutes.concat(routes)
      }
    }
    
    const actions = {
      generateRoutes({ commit }, token) {
        return new Promise(resolve => {
          // 通过token从后端获取用户菜单,并加入全局状态
          fetchUserMenuList(token).then(res => {
            const menuData = Object.assign([], res.data)
            const tempAsyncRoutes = Object.assign([], asyncRoutes)
            const accessedRoutes = generaMenu(tempAsyncRoutes, menuData)
    
            commit('SET_ROUTES', accessedRoutes)
            resolve(accessedRoutes)
          }).catch(error => {
            console.log(error)
          })
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    
    

    2.3、在vuex中注册permission模块

    ? 如果使用的是vue-element-admin请跳过此步,因为它在src\store\index.js中自动注册了src\store\modules下的所有模块。如果你使用的是vue-element-template,可以参考admin,将index.js文件改造一下,也可以手动import一下。

    import Vue from 'vue'
    import Vuex from 'vuex'
    import getters from './getters'
    
    Vue.use(Vuex)
    
    // https://webpack.js.org/guides/dependency-management/#requirecontext
    const modulesFiles = require.context('./modules', true, /\.js$/)
    
    // you do not need `import app from './modules/app'`
    // it will auto require all vuex module from modules file
    const modules = modulesFiles.keys().reduce((modules, modulePath) => {
      // set './app.js' => 'app'
      const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
      const value = modulesFiles(modulePath)
      modules[moduleName] = value.default
      return modules
    }, {})
    
    const store = new Vuex.Store({
      modules,
      getters
    })
    
    export default store
    
    

    2.4、在getters中增加路由状态

    ? 在vuex路径src\store\getters.js添加menusRoutes状态

    menusRoutes: state => state.permission.routes
    

    image-20210428151938637

    2.5、修改菜单生成数据来源

    ? 在路径src\layout\components\Sidebar\index.vue修改routes数据来源,原来数据源是路由,改为从vuex中获取。

        routes() {
          // return this.$router.options.routes
          return this.$store.getters.menusRoutes
        },
    

    image-20210428152509681

    ? 至此,从后端获取菜单数据到页面展示的逻辑已经完毕,下面开始在登陆后进行调用。

    2.6、登陆后获取菜单

    ? 在vuex路径src\store\modules\user.js的login方法中,加入登陆成功通过token获取菜单生成路由逻辑。

              // 获取菜单,调用其他文件中actions时必须加 { root: true }
              dispatch('permission/generateRoutes', data, { root: true }).then((accessRoutes) => {
                router.addRoutes(accessRoutes)
              })
    

    image-20210428153210137

    2.7、解决刷新后页面空白

    ? 以上内容已经可以实现登陆后展示左侧菜单功能,但是会发现每次刷新页面后,页面都会变空白。这是因为在页面刷新时,会重新加载vue实例,vuex的store中的数据会被重新赋值,导致我们存在vuex中的路由信息被清空。

    ? 在src\permission.js中增加重新获取路由代码。

              const accessRoutes = await store.dispatch('permission/generateRoutes', store.getters.token)
              router.addRoutes(accessRoutes)
              next({ ...to, replace: true })
    

    image-20210428155350723

    3、总结

    ? 至此根据用户信息动态获取菜单内容已经全部完成。

    转载请注明出处,原文链接:

    https://www.cnblogs.com/gaozejie/p/14714616.html

    bk