vue动态菜单

110 阅读2分钟

当一个项目还在原始阶段的时候,页面菜单路由,一般都是定义在前端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

改动态路由的代码。

  1. 进入路由页面时,在路由守卫中,判断是否加载过菜单,若没有,则去获取菜单(这里把是否加载过菜单的值标识,放在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
  }
})
  1. 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
}