路由数据

完整版的ibps 路由设置文件在 src/router/routes.js。

动态路由

addRoutes

在之前通过后端动态返回前端路由一直很难做的,因为vue-router必须是要vue在实例化之前就挂载上去的,不太方便动态改变。不过好在vue2.2.0以后新增了router.addRoutes
具体代码 src/router/routes.js。

具体实现

  1. 创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。
  2. 当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。
  3. 调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
    使用vuex管理路由表,根据vuex中可访问的路由渲染顶部和侧边栏组件。

    router.js

    首先我们实现router.js路由表(src/router/utils.js)
import layoutHeaderAside from '@/layout/header-aside'
import menuUtil from '@/utils/menu'
// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载
const _import = require('@/utils/util.import.' + process.env.NODE_ENV)
const meta = { auth: true }
/**
 * 动态布局
 */
function getLayout() {
  return layoutHeaderAside
}
/**
 * 错误页面
 */
const errorPage = {
  path: '*',
  redirect: '/404',
  hidden: true
}
const errorUrl = '/system/error/404'

const idKey = menuUtil.ID_KEY
const labelKey = menuUtil.LABEL_KEY
const nameKey = menuUtil.NAME_KEY
const iconKey = menuUtil.ICON_KEY
const parentIdKey = menuUtil.PARENT_KEY
const childrenKey = menuUtil.CHILD_KEY
const urlKey = menuUtil.URL_KEY
const layoutKey = 'layout'
const defaultRouterAlias = '/router-alias/'

// 异步挂载的路由
// 动态需要根据权限加载的路由表 该路由表通过后台获取
export function generateRoutes(menus) {
  const asyncRouterMap = []
  for (const menu of menus) {
    asyncRouterMap.push(generateTopRoute(menu))
  }
  asyncRouterMap.push(errorPage)
  return asyncRouterMap
}

/**
 * 构建第一级路由
 * @param {*} menu
 */
function generateTopRoute(menu) {
  const router = {
    id: menu[idKey],
    parentId: menu[parentIdKey],
    path: '/' + menu[nameKey],
    alias: defaultRouterAlias + menu[nameKey],
    name: menu[nameKey],
    component: getLayout(menu[layoutKey]),
    meta: {
      title: menu[labelKey],
      icon: menu[iconKey] || 'file-o',
      name: menu[nameKey],
      defaultUrl: menu[urlKey],
      ...meta
    }
  }
  if (menu[childrenKey] && menu[childrenKey].length > 0) {
    router.children = generateSubRoutes(menu[childrenKey])
  } else { // 添加顶部默认节点
    router.children = [{
      id: menu[idKey],
      parentId: menu[parentIdKey],
      path: 'index',
      name: menu[nameKey],
      alias: defaultRouterAlias + menu[nameKey],
      component: getComputedUrl(menu[urlKey]),
      meta: {
        title: menu[labelKey],
        icon: menu[iconKey] || 'file-o',
        name: menu[nameKey],
        defaultUrl: menu[urlKey],
        ...meta
      }
    }]
  }
  return router
}

/**
 * 构建子路由
 * @param {*} menus
 */
function generateSubRoutes(menus) {
  const pool = []
  const push = function(menus, namePrefix = []) {
    menus.forEach(menu => {
      const router = {
        id: menu[idKey],
        parentId: menu[parentIdKey],
        path: [...namePrefix, menu[nameKey]].join('/'),
        name: [...namePrefix, menu[nameKey]].join('-'),
        alias: defaultRouterAlias + menu[nameKey],
        component: getComputedUrl(menu[urlKey]),
        meta: {
          title: menu[labelKey],
          icon: menu[iconKey] || 'file-o',
          name: menu[nameKey],
          defaultUrl: menu[urlKey],
          ...meta
        }
      }

      if (menu[childrenKey] && menu[childrenKey].length > 0) {
        push(menu[childrenKey], [...namePrefix, menu[nameKey]])
      } else {
        pool.push({
          ...router
        })
      }
    })
  }
  push(menus)
  return pool
}

/**
 * 是否是iframe
 * @param {*} url
 */
function isHttp(url) {
  if (url === null || url === undefined || url === '') return false
  return !!(url.indexOf('http') !== -1 || url.indexOf('https') !== -1)
}
/**
 * 获取 组件url
 * @param {*} menu
 */
function getComputedUrl(url) {
  if (!url) return _import(errorUrl)
  try {
    if (isHttp(url)) {
      return _import('/system/iframe/index')
    } else if (url.indexOf('/d/') > -1) { // 数据模版
      return _import('/platform/data/dataTemplate/template-list')
    } else {
      return _import(convertUrl(url)) || _import(errorUrl)
    }
  } catch (error) {
    // console.warn(error)
    return _import(errorUrl)
  }
}
/**
 * 转换url 避免多余‘/’
 * @param {*} url
 */
function convertUrl(url) {
  const newUrl = '/' + url
  return newUrl === '/' ? '/' : newUrl.replace(/\/\//g, '/').replace(/\/$/, '')
}

这里我们根据 vue-router官方推荐 的方法通过meta标签来标示改页面能访问的权限有哪些。如meta: { icon: menu[iconKey] || ‘file-o’} 表示展示的图标。

注意事项:这里有一个需要非常注意的地方就是 404 页面一定要最后加载,如果放在constantRouterMap一同声明了404,后面的所以页面都会被拦截到404,详细的问题见addRoutes when you’ve got a wildcard route for 404s does not work

FAQ

  1. 怎么新增个路由菜单不显示菜单里面,代码里面进行访问
    菜单管理-》添加

代码里面使用:

this.$router.push("路由地址")

// 或者别名路由
const alias = '别名'
this.$router.push('/router-alias/' + alias)

//更多路由传参
https://router.vuejs.org/zh/guide/essentials/navigation.html

文档更新时间: 2020-04-08 16:26   作者:hugh