Vue-Element-admin 的动态路由手把手教学

2,698 阅读2分钟

Vue-Element-admin 的动态路由手把手教学

概要

本文讲述了如何在vue-element-admin的基础模板下完成动态路由的功能 整篇的登录权限流程再此就不赘述了,直接上代码 喜欢的小伙伴或者有帮助的小伙伴,麻烦点个赞 本人还自己搭了带有权限和tabview的模板 欢迎小伙伴们star Vue-Element-admin模板

1./src/store/user.js文件更改

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

const state = {
  token: getToken(),
  name: '',
  avatar: '',
  introduction: '',
  roles: [],
  menus: [] //动态路由菜单  <=== 修改部分
}

const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_INTRODUCTION: (state, introduction) => {
    state.introduction = introduction
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  },
  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(async response => {
          const { data } = response

          if (!data) {
            reject('Verification failed, please Login again.')
          }

          const { roles, name, avatar, introduction } = data
          const key = state.token.split('-')[0]
          const res = await getRoles()
          const menusList = res.data     //<=== 修改部分
          const newMenusList = menusList.filter(v => {  	//<=== 修改部分
            if (v.key === key) {
              return v
            }
          })
          console.log(`newMenusList[0].routes`, newMenusList[0].routes)
          const menus = newMenusList[0].routes  //<=== 修改部分
          // const key = 
          // const menus = [    //<=== 修改部分   menus数据格式
          //   {
          //     path: "/employee",
          //     component: "layout/Layout",
          //     redirect: "/employee/index",
          //     children: [
          //       {
          //         path: "index",
          //         component: "employee/index",
          //         name: "C",
          //         meta: {
          //           title: "员工管理",
          //           icon: "peoples",
          //           noCache: true,
          //           roles: ["admin"]
          //         }
          //       }
          //     ]
          //   },
          //   {
          //     path: "/permission",
          //     component: 'layout/Layout',
          //     redirect: "/permission/page",
          //     name: "Permission",
          //     meta: {
          //       title: "权限管理",
          //       icon: "lock",
          //       roles: ["admin"]
          //     },
          //     children: [
          //       {
          //         path: "role",
          //         component: "permission/role",
          //         name: "RolePermission",
          //         meta: {
          //           title: "权限管理",
          //           roles: ["admin"]
          //         }
          //       }
          //     ]
          //   }
          // ]
          if (!roles || roles.length <= 0) {
            reject('getInfo: roles must be a non-null array!')
          }

          commit('SET_ROLES', roles)
          commit('SET_NAME', name)
          commit('SET_AVATAR', avatar)
          commit('SET_INTRODUCTION', introduction)
          commit('SET_MENUS', menus)		//<=== 修改部分
          resolve(data)
        })
        .catch(error => {
          reject(error)
        })
    })
  },

  // user logout
  logout({ commit, state, dispatch }) {
    return new Promise((resolve, reject) => {
      logout(state.token)
        .then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          removeToken()
          resetRouter()

          // reset visited views and cached views
          // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
          dispatch('tagsView/delAllViews', null, { root: true })

          resolve()
        })
        .catch(error => {
          reject(error)
        })
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      commit('SET_TOKEN', '')
      commit('SET_ROLES', [])
      removeToken()
      resolve()
    })
  },

  // dynamically modify permissions
  async changeRoles({ commit, dispatch }, role) {
    const token = role + '-token'

    commit('SET_TOKEN', token)
    setToken(token)

    const { roles } = await dispatch('getInfo')

    resetRouter()

    // generate accessible routes map based on roles
    const accessRoutes = await dispatch('permission/generateRoutes', roles, {
      root: true
    })
    // dynamically add accessible routes
    router.addRoutes(accessRoutes)

    // reset visited views and cached views
    dispatch('tagsView/delAllViews', null, { root: true })
  }
}

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

2./src/router/建立新文件_import_development.js

	//用于渲染后台渲染的数据转换为组件  这样写 为了保证自带的懒加载可以加载出组件 否则会报错
    module.exports = file => {
      return (resolve) => require([`@/views/${file}`], resolve)
    }

3./src/permission.js

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_development')	//<=== 修改部分

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

const whiteList = ['/login', '/auth-redirect'] // 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() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
    } else {
      // determine whether the user has obtained his permission roles through getInfo
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          // get user info
          // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
          await store.dispatch('user/getInfo')
          // const { roles } = await store.dispatch("user/getInfo");
          const menus = filtersAsyncRouter(store.getters.menus)	//<=== 修改部分
          console.log(menus)
          global.antRouter = menus	//<=== 修改部分
          router.addRoutes(menus)		//<=== 修改部分

          // generate accessible routes map based on roles
          // const accessRoutes = await store.dispatch(
          //   'permission/generateRoutes',
          //   roles
          // )

          // dynamically add accessible routes
          // router.addRoutes(accessRoutes)

          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
          next({ ...to, replace: true })
        } 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()
})

// 过滤服务器传来的数据,转换为组件对象		//<=== 修改部分
const filtersAsyncRouter = asyncRouterMap => {
  const accessRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'layout/Layout') {
        route.component = Layout
      } else {
        route.component = _import(route.component)
      }
    }
    if (route.children && route.children.length) {
      route.children = filtersAsyncRouter(route.children)
    }
    return true
  })
  return accessRouters
}

4./src/layout/sidebar/index.vue

<template>
  <div :class="{'has-logo':showLogo}">
    <logo v-if="showLogo" :collapse="isCollapse" />
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="variables.menuBg"
        :text-color="variables.menuText"
        :unique-opened="false"
        :active-text-color="variables.menuActiveText"
        :collapse-transition="false"
        mode="vertical"
      >
        <sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" /> //<=== 修改部分
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'

export default {
  components: { SidebarItem, Logo },
  computed: {
    ...mapGetters([
      'permission_routes',
      'sidebar',
      'menus'  //<=== 修改部分
    ]),
    routes() { //<=== 修改部分
      console.log('routes', this.$router.options.routes.concat(global.antRouter))
      return this.$router.options.routes.concat(global.antRouter)
    },
    activeMenu() {
      const route = this.$route
      const { meta, path } = route
      // if set path, the sidebar will highlight the path you set
      if (meta.activeMenu) {
        return meta.activeMenu
      }
      return path
    },
    showLogo() {
      return this.$store.state.settings.sidebarLogo
    },
    variables() {
      return variables
    },
    isCollapse() {
      return !this.sidebar.opened
    }
  }
}
</script>