使用vue-element-admin框架從後端動態獲取選單

#Empty發表於2021-04-28

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

相關文章