vue-element-admin 实现动态路由(从后台查询出菜单列表绑定侧边栏)
1. 在路由实例中保留基础路由
router/index.js中只需要保留基础路由,其他的都删了
2. 获取用户菜单,并保存到Vuex中
stroe/modules/user.js中,有个getInfo方法查询用户基本信息,返回了用户的菜单列表
// 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.') } console.log(data) const menus = [{ path: '/books', component: 'Layout', children: [{ path: 'index', name: 'AddressBook', component: 'workbench/addressbook', meta: { title: '通讯录', icon: 'company' } }] }, { path: '/systool', component: 'Layout', redirect: '/systool/coder', name: 'SysTool', meta: { title: '实验室', icon: 'example' }, children: [ { path: 'calendar', name: 'Calendar', component: 'workbench/calendar', meta: { title: '日程', icon: 'table' } } ] }] const { name, avatar, companyName, employeeid } = data commit('SET_NAME', name) commit('SET_AVATAR', avatar) commit('SET_CMPNAME', companyName) commit('SET_USERID', employeeid) commit('SET_MENUS', menus) resolve(data) }).catch(error => { reject(error) }) }) }
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')
A,组件导入 —— _import
//获取组件的方法 const _import = require('./router/_import_' + process.env.NODE_ENV) // ....... //导入路径下的组件 route.component = _import(route.path)
B,在路由钩子中,过滤路由,并生成路由
核心在src目录下的permission.js中,router.beforeEach路由钩子
1 import router from './router' 2 import store from './store' 3 import { 4 Message 5 } from 'element-ui' 6 import NProgress from 'nprogress' // progress bar 7 import 'nprogress/nprogress.css' // progress bar style 8 import { 9 getToken 10 } from '@/utils/auth' // get token from cookie 11 import getPageTitle from '@/utils/get-page-title' 12 import Layout from '@/layout' 13 const _import = require('./router/_import_' + process.env.NODE_ENV) // 获取组件的方法 14 15 NProgress.configure({ 16 showSpinner: false 17 }) // NProgress Configuration 18 19 const whiteList = ['/login'] // no redirect whitelist 20 21 router.beforeEach(async(to, from, next) => { 22 // start progress bar 23 NProgress.start() 24 25 // set page title 26 document.title = getPageTitle(to.meta.title) 27 28 // determine whether the user has logged in 29 const hasToken = getToken() 30 31 if (hasToken) { 32 if (to.path === '/login') { 33 // if is logged in, redirect to the home page 34 next({ 35 path: '/' 36 }) 37 NProgress.done() 38 } else { 39 const hasGetUserInfo = store.getters.name 40 if (hasGetUserInfo) { 41 next() 42 } else { 43 try { 44 // get user info 45 await store.dispatch('user/getInfo') 46 if (store.getters.menus.length < 1) { 47 global.antRouter = [] 48 next() 49 } 50 const menus = filterAsyncRouter(store.getters.menus) // 1.过滤路由 51 router.addRoutes(menus) // 2.动态添加路由 52 global.antRouter = menus // 3.将路由数据传递给全局变量,做侧边栏菜单渲染工作 53 next({ 54 ...to, 55 replace: true 56 }) // hack方法 确保addRoutes已完成 ,set the replace 57 } catch (error) { 58 // remove token and go to login page to re-login 59 await store.dispatch('user/resetToken') 60 Message.error(error || 'Has Error') 61 next(`/login?redirect=${to.path}`) 62 NProgress.done() 63 } 64 } 65 } 66 } else { 67 /* has no token*/ 68 69 if (whiteList.indexOf(to.path) !== -1) { 70 // in the free login whitelist, go directly 71 next() 72 } else { 73 // other pages that do not have permission to access are redirected to the login page. 74 next(`/login?redirect=${to.path}`) 75 NProgress.done() 76 } 77 } 78 }) 79 80 router.afterEach(() => { 81 // finish progress bar 82 NProgress.done() 83 }) 84 85 // 遍历后台传来的路由字符串,转换为组件对象 86 function filterAsyncRouter(asyncRouterMap) { 87 const accessedRouters = asyncRouterMap.filter(route => { 88 if (route.component) { 89 if (route.component === 'Layout') { 90 route.component = Layout 91 } else { 92 route.component = _import(route.component) // 导入组件 93 } 94 } 95 if (route.children && route.children.length) { 96 route.children = filterAsyncRouter(route.children) 97 } 98 return true 99 }) 100 101 return accessedRouters 102 }