最近项目要求鲁有需要动态获取,从后端返回数据进行处理。我的项目模板是基于element-damin-template的。官方文档也有介绍
https://panjiachen.github.io/vue-element-admin-site/zh/guide/essentials/permission.html#%E9%80%BB%E8%BE%91%E4%BF%AE%E6%94%B9
通常的路由使我们自己在router/index里面自己定义的路由,写死的一些路由,这些路由在加载时如果不做处理就会直接全部加载,而后台数据一般我们需要做权限控制。一般来说都是需要后台返回我们这个账号所能展示的路由,由我们动态加载。
首先,我们需要后端接口,携带这些权限路由信息。
其次,我们要想办法加载到我们的router中。
import Layout from '@/layout/index'
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const constantRoutes = [
// 登录页
{
path: '/login',
component: (resolve) => require(['@/views/login/index'], resolve),
hidden: true
},
// 首页
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: (resolve) => require(['@/views/dashboard/index'], resolve),
meta: { title: '首页', affix: true }
}]
},
//报错页面
{
path: '/404',
component: (resolve) => require(['@/views/404'], resolve),
hidden: true
},
]
const createRouter = () => new Router({
mode: 'history',
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher
}
router.$addRoutes = function(params) {
router.matcher = new Router({ mode: 'history' }).matcher;
router.addRoutes(params)
}
export default router
import { getMenus } from '@/api/setUp/menu';
import Layout from '@/layout/index';
import vue from '@/main';
import { constantRoutes } from '@/router';
const permission = {
state: {
routers: [],
addRouters: []
},
mutations: {
SET_ROUTES: (state, router) => {
state.addRouters = router;
state.routers = constantRoutes.concat(router);
}
},
actions: {
// 生成路由
GenerateRoutes({ commit }) {
return new Promise(resolve => {
// isLogin: 0 返回所有菜单 isLogin: 1 根据角色返回对应的菜单
let data = {
isLogin: 1
}
// 获取后端返回的路由表
getMenus(data).then(res => {
// 处理后端返回的路由表转化为嵌套模式
for (var i = 0; i < res.data.length; i++) {
res.data[i].children = []
}
let routes = vue.handleTree(res.data, "id");
// 调用 getAsyncRoutes转化为我们需要的正确路由格式
let accessedRoutes = getAsyncRoutes(routes)
//添加404
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
// 设置综合路由表
commit('SET_ROUTES', accessedRoutes)
// 导出综合路由表
resolve(permission.state.routers)
})
})
}
}
}
/**
1. 把后台返回菜单组装成routes要求的格式
2. @param {*} routes
*/
export function getAsyncRoutes(routes) {
const res = []
routes.forEach(item => {
const newItem = {}
if (item.component) {
if (item.component === 'layout') {
newItem.component = Layout
} else {
newItem.component = loadView(item.component)
//这种格式的路由加载方式会出现问题,具体原因可以了解下webpack,我们使用require方式就OK了
// newItem.component = () =>
// import (`@/views/${item.component}`)
}
}
newItem.meta = {
title: item.name
}
newItem.name = item.path
newItem.path = `/${item.path}`
if (item.children && item.children.length) {
newItem.children = getAsyncRoutes(item.children)
}
res.push(newItem)
})
return res
}
export const loadView = (view) => { // 路由懒加载
return (resolve) => require([`@/views/${view}`], resolve)
}
export default permission
这个里面,我们后端返回的数据需要进行两次处理,大家根据后端数据格式酌情处理就可以。
3. 之后我们在getters.js里面设置
permission_routes: state => state.permission.routers
并且在layout的sidebar/index.vue的computed引入,我的项目导航栏不太一样就不多展示了
...mapGetters(["permission_routes","sidebar"]),
4.进入permission.js文件,这个文件是我们的路由拦截配置文件。在这里面调用我们store里设置的GenerateRoutes,然后添加router中
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import routers from './router'
import store from './store'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // 白名单
routers.beforeEach(async(to, from, next) => {
// 进度条开始
NProgress.start()
// 页面标题
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
if (hasGetUserInfo) {
next()
} else {
// 重点就是在这里面进行配置!!!!
try {
// 确认用户登录
await store.dispatch('user/getInfo')
// 调用store方法获取路由信息并添加到路由表中
const accessRoutes = await store.dispatch('GenerateRoutes')
// 通过手动的$addRoutes方法删除旧的路由表并且添加
routers.$addRoutes(accessRoutes)
routers.options.routes = accessRoutes
next({...to, replace: true })
} catch (error) {
// 删除令牌并转到登录页面重新登录
await store.dispatch('user/resetToken')
Message.error('Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// 在免费登录白名单中,直接进入
next()
} else {
//其他没有访问权限的页面将被重定向到登录页面.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
routers.afterEach(() => {
// finish progress bar
NProgress.done()
})
这样一套流程下来基本上就完事了。
总结:1.定义公共路由;
2.store中设置获取路由的方法(获取并处理后端返回的路由表数据为我们需要的路由格式)
3.在路由拦截中调用store的方法获取路由数据并添加到router中实现动态权限控制
中间遇到过多次很有趣的问题,当时忘记记录,如有问题,欢迎讨论。
好记性不如烂笔头,早起的鸟儿有虫吃,冲鸭!!!