vue根据后端返回路由动态渲染页面

1,700 阅读1分钟

后端返回路由格式:

[
  {
    "path": "/node",
    "component": "Layout",
    "children": [
      {
        "path": "index",
        "component": "/node/index",
        "meta": {
          "icon": "host",
          "title": "主机管理"
        },
        "name": "node"
      }
    ]
  },
  {
    "path": "/cluster",
    "component": "Layout",
    "children": [
      {
        "path": "index",
        "component": "/cluster/index",
        "meta": {
          "icon": "cluster",
          "title": "集群管理"
        },
        "name": "cluster"
      }
    ]
  },
  {
    "path": "/storage",
    "component": "Layout",
    "children": [
      {
        "path": "index",
        "component": "/storage/index",
        "meta": {
          "icon": "storage",
          "title": "存储管理"
        },
        "name": "storage"
      }
    ]
  },
  {
    "redirect": "/vm",
    "path": "/vmManage",
    "component": "Layout",
    "children": [
      {
        "path": "/vm",
        "component": "/vm/index",
        "meta": {
          "icon": "vm",
          "title": "虚拟机列表"
        },
        "name": "vm"
      }
    ]
  },
  {
    "redirect": "/hostResource",
    "path": "/resource",
    "component": "Layout",
    "children": [
      {
        "path": "/hostResource",
        "component": "/resource_monitor/host_resource/index",
        "meta": {
          "icon": "host",
          "title": "主机资源"
        },
        "name": "hostResource"
      },
      {
        "path": "/vmResource",
        "component": "/resource_monitor/VM_resource/index",
        "meta": {
          "icon": "vm",
          "title": "虚拟机资源"
        },
        "name": "vmResource"
      }
    ],
    "meta": {
      "icon": "resource",
      "title": "资源监控"
    },
    "name": "resource"
  },
  {
    "redirect": "/404",
    "path": "*",
    "hidden": true
  }
]

处理后端返回的路由表中的 component ,将 "Layout" 转换为组件对象,children中component为页面组件的路径

将默认路由和动态路由合并constantRoutes.concat(routes),最后router.addRoutes()

前置导航守卫

import router from './router'
import store from './store'
import NProgress from 'nprogress'
NProgress.configure({ showSpinner: false })

const whiteList = ['/login']

router.beforeEach(async(to, from, next) => {
  // 关闭l所有layer弹窗
  Layer.prototype.$layer.closeAll()
  NProgress.start()
  document.title = getPageTitle(to.meta.title)
  // 去往登录界面的路由跳转-->路由放行
  if (to.path === '/login' && !sessionStorage.getItem('roles')) {
    store.state.permission.routes = []
    next()
  } else {
    // 判断用户是否已经登录
    await loginpermit().then(async(res) => {
      if (res && sessionStorage.getItem('roles')) {
        try {
          // 判断是否进行路由过滤
          if (store.state.permission.routes.length <= 0) {
            const role = [sessionStorage.getItem('roles')]
            // 获取动态路由信息
            const accessRoutes = await store.dispatch('permission/generateRoutes', role)
            console.log(accessRoutes)
            // 添加路由权限
            router.addRoutes(accessRoutes)
            // 赋值渲染路由
            router.options.routes = store.state.permission.routes
            const rolePage = {
              'sysadmin': { path: '/node/index' },
              'secadmin': { path: '/terminal/index' },
              'auditadmin': { path: '/eventAudit/index' },
              'user': { path: '/vmManage' },
              'monitoradmin': { path: '/monitor/index' }
            }
            // 保证权限添加完成并重新进行跳转
            next({ ...rolePage[role], replace: true })
            // next({ path: to.path, replace: true })
          } else {
            // 已经进行路由过滤-->放行
            next()
            NProgress.done()
          }
        } catch (error) {
          // 捕获异常-->主要是获取用户信息的异常,此处是必要的,返回数据异常极容易造成路由过滤问题,
          console.log('add permission error', error)
        }
      } else {
        logout()
        // 不存在登录令牌,校验路由白名单-->此处是必要的,首次加载路由必须通过该方式进行渲染
        if (whiteList.indexOf(to.path) !== -1) {
          next()
          NProgress.done()
        } else {
          // 路由指向的位置不在白名单范围内,且用户并没有登录令牌,直接跳转登录界面-->跳转白名单内容即可,会重新执行beforeEach,通过白名单逻辑进行渲染
          await store.dispatch('user/resetToken')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }).catch(async() => {
      await store.dispatch('user/resetToken')
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    })
  }
})

router.afterEach(() => {
  NProgress.done()
})

在获取动态路由信息时,对路由表进行处理

// 字符串路径转为组件对象

// 将后端传回的"componentUrl": "Layout", 转为"component": Layout组件对象

export const loadViewsd = (view) => {

    // 使用异步组件 实现路由懒加载 提升首屏加载速度

    // 这个特殊的 `require` 语法将会告诉 webpack

    // 自动将你的构建代码切割成多个包

    return function(resolve) {
        require(['@/views/cloud_desk' + view + '.vue'], resolve)
    }
    
    // CommonJS模块 运行时加载 获取到对象 编译时无法做静态优化
    // 首屏加载速度慢
    // return require('@/views/cloud_desk' + view + '.vue').default
    // return require('@/views' + view + '.vue').default

}
// 格式化route,处理component
export function formatRouter(routes) {
  routes.forEach((route) => {
    if (route.component) {
      // Layout组件特殊处理
      if (route.component === 'Layout') {
        route.component = Layout
      } else {
        route.component = loadViewsd(route.component)
      }
    }
    if (route.children && route.children.length) {
      route.children = formatRouter(route.children)
    }
  })
  return routes
}