vue-element-admin 实现动态路由(从后台查询出菜单列表绑定侧边栏)

1. 在路由实例中保留基础路由

router/index.js中只需要保留基础路由,其他的都删了

vue-element-admin 实现动态路由(从后台查询出菜单列表绑定侧边栏)_第1张图片

2. 获取用户菜单,并保存到Vuex中

stroe/modules/user.js中,有个getInfo方法查询用户基本信息,返回了用户的菜单列表

import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter } from '@/router'

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: ''
  }
}

const state = getDefaultState()

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_MENUS: (state, menus) => {
    state.menus = menus
  }
}

const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response
        if (!data) {
          reject('Verification failed, please Login again.')
        }
        //模拟请求回来的栏目树数据,后端根据角色递归组装
        const menus =
          [
            {
              path: '/a',
              component: 'Layout',
              meta: { title: '请求栏目', icon: 'form' },
              children: [
                {
                  path: '/form',
                  name: 'form',
                  component: 'form/index',    //该组件位置在views/form/index.vue,
                  // form前加不加 /,取决于你的router/_import_  文件中的@/view、后面是否有/
                  meta: { title: '通讯录', icon: 'form' }
                },
                {
                  path: '/table',
                  name: 'table',
                  component: 'table/index',    //该组件位置在views/form/index.vue,
                  // form前加不加 /,取决于你的router/_import_  文件中的@/view、后面是否有/
                  meta: { title: '列表', icon: 'table' }
                }
              ]
            }
          ]

        //如果需要404 页面,请在此处添加
        menus.push(
          {
            path: '/404',
            component: '404',
            hidden: true
          },
          {
            path: '*',
            redirect: '/404',
            hidden: true
          })
        const { name, avatar } = data
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        commit('SET_MENUS', menus)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        removeToken() // must remove  token  first
        resetRouter()
        commit('RESET_STATE')
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // must remove  token  first
      commit('RESET_STATE')
      resolve()
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

 store/getter.js

const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  cmpname: state => state.user.cmpname,
  userid: state => state.user.userid,
  menus: state => state.user.menus
}
export default getters

3.动态生成权限路由(核心)

根据环境配置导入组件,在vue中,将菜单路径作为参数,实现路由地址的注入

在 src/router 文件夹下,建立两个文件,各只需添加一行代码, 定义导入方法

src/router/_import_development.js
//开发环境导入组件
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+

---------------------------------------------------------------------

src/router/_import_production.js
//生产环境导入组件
module.exports = file => () => import('@/views/' + file + '.vue')

 说明:组件导入 —— _import

//获取组件的方法
const _import = require('./router/_import_' + process.env.NODE_ENV)

// .......

//导入路径下的组件
route.component = _import(route.path)

4.使用

在路由钩子中,过滤路由,并生成路由

核心在src目录下的permission.js中,router.beforeEach路由钩子

import router from './router'
import store from './store'
import {
  Message
} from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import {
  getToken
} from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
import Layout from '@/layout'
const _import = require('./router/_import_' + process.env.NODE_ENV) // 获取组件的方法

NProgress.configure({
  showSpinner: false
}) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({
        path: '/'
      })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo')
          if (store.getters.menus.length < 1) {
            global.antRouter = []
            next()
          }
          const menus = filterAsyncRouter(store.getters.menus) // 1.过滤路由
          router.addRoutes(menus) // 2.动态添加路由
          global.antRouter = menus // 3.将路由数据传递给全局变量,做侧边栏菜单渲染工作
          next({
            ...to,
            replace: true
          }) // hack方法 确保addRoutes已完成 ,set the replace
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})

// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') {
        route.component = Layout
      } else {
        route.component = _import(route.component) // 导入组件
      }
    }
    if (route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })

  return accessedRouters
}

5.最后一步,合并路由

vue-element-admin 实现动态路由(从后台查询出菜单列表绑定侧边栏)_第2张图片

 

转载地址:https://www.cnblogs.com/langhaoabcd/p/11346227.html

你可能感兴趣的:(vue,Elementui,vue.js,es6)