当一个项目还在原始阶段的时候,页面菜单路由,一般都是定义在前端router文件夹下。router/index.js直接引入相关路由文件,定义,渲染、展示。
但当项目进入到一定的阶段,开始卖给不同客户,可能要分出不同的版本:普通版、升级版。就会存在部分模块不想开放给客户使用的问题。或者说,同一个系统,不同的用户角色登录,拥有的操作权限是不一致的。
于是对菜单权限做出管控,菜单就要改成通过配置动态生成,不再是静态写在前端代码里。毕竟改来改去也非常麻烦。是在permission.js路由守卫中和router/index.js中处理。
改前代码,静态路由菜单,如下。
// 省略部分代码
export const constantRoutes = []
const createRouter = (callback) => {
constantRoutes.push(...DEFAULT_ROUTERS)
let route = new Router({
mode: 'history',
base: '/',
routes: constantRoutes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return {
x: 0,
y: 0
}
}
}
})
callback && callback()
return route
}
const router = createRouter()
export default router
改动态路由的代码。
- 进入路由页面时,在路由守卫中,判断是否加载过菜单,若没有,则去获取菜单(这里把是否加载过菜单的值标识,放在store中)
import { menuList, constantRoutes } from './router'
router.beforeEach(async (to, from, next) => {
const isLoadMenu = store.state.asyncMenu.isAsyncRoutesLoad
if (!isLoadMenu) {
// 未过获取菜单
store.dispatch('asyncMenu/changeLoadMenuState', true)
const list = await menuList()
constantRoutes.push(...list)
list.forEach((item) => router.addRoute(item))
// 404 page must be placed at the end !!!
router.addRoute({ path: '*', redirect: '/404', hidden: true })
// 跳转到目标页面
next({ ...to, replace: true })
NProgress.done()
return
}
})
constantRoutes的值是从router/index中读的,会双向绑定,路由菜单的值,当创建createRouter时,方法读取时,就能读取到新的菜单配置,并生成。不过需要注意的事,后端返回的菜单路径是string,前端需要转义一下,指向对应的组件,才能使用。
let routeConfig = (list, parentPath = '') => {
list.forEach((v) => {
v.redirect = v.thirdPartyJumpLink
v.componentPath = `${parentPath}${v.path}`
if (v.component === 'Layout') {
v.component = Layout
} else if (v.component === 'LayoutEmpty') {
v.component = LayoutEmpty
} else {
v.component = resolveComponent(v.component)
}
if (v.dynamicField) {
try {
mergeObject(JSON.parse(v.dynamicField), v, true)
} catch (e) {}
}
if (v.children) {
routeConfig(v.children, `${v.componentPath}/`)
}
})
return list
}