前后端分离动态加载菜单
当用户登录之后获取用户信息的时候,将获取到的路由信息存储到vuex中的全局数据区
在getters.js文件下定一个存储的变量
在router文件下创建两个文件
_import_development.js
module.exports = file => require('@/views/' + file + '.vue').default
_import_production.js
module.exports = file => () => import('@/views/' + file + '.vue')
在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_' + process.env.NODE_ENV) // process.env.NODE_ENV为生产环境下获取组件的方法(.env.staging文件有个环境变量为NODE_ENV)
NProgress.configure({ showSpinner: false }) // NProgress请求条配置
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)
// 判断当前用户是否登录
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// 如果用户已登录,重定向到根目录
next({ path: '/' })
NProgress.done()
} else {
const hasGetUserInfo = store.getters.name
// console.log(hasGetUserInfo)
if (hasGetUserInfo) {
next()
} else {
try {
// 已登录情况下,获取用户信息
await store.dispatch('user/getInfo', hasToken)
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
// next()
} catch (error) {
// 出现错误移除token重定向到登录页面
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
// Message({
// type: 'error',
// message: 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
})
accessedRouters.push({ path: '*', redirect: '/404', hidden: true }) //必须要将404的路由加在动态路由的后面,否则登录成功后刷新页面会出现404
return accessedRouters
}
将动态路由和静态路由拼接
后端获取的路由的格式:
[{
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' }
}
]
}]
静态路由:
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: 'Dashboard', icon: 'dashboard' }
}]
}
]
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
//github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
注意:
1、404路由一定要放在动态路由的后面
2、注意要在VUEx定义存储的全局变量,关于更多vuex的内容参考官方文档