一文彻底搞懂弄清Vue Router4+vite4后台管理的动态路由问题

前后端分离可以说是当下最火的开发方式,充分将后端从前端的繁琐工作中解放了出来,也让更多之前后端瞧不上的前端有了一席之地,诞生了前端工程师这个称呼和岗位,但通过笔者的观察前端工程化其实就是抄袭了后端的一些开发思想所诞生的产品及框架。

比如什么模块化,路由,过滤器,自定义标签等等,无非都是后端很早就有的概念,但说归说,闹归闹,程序员无非就是跟随时代潮流,不断的折腾,不断的搞自己,为难自己,提升自己,不断的学习技术,然后开发更新的技术自己为难自己,当然要说前后端分离有什么优势,当然是有,后端轻松了,更专注逻辑了,前端不再只关心界面了,还要参与逻辑,技术更牛逼了。

但你要问哪个更苦逼了,我觉得是前端,要不然前端工程师的薪资为什么会水涨船高呢?老板也更痛苦了,之前一个后端既能写逻辑又能写界面,现在非得要分开,成本上升了!

当然,对于我们打工人码农来说是好事,学一学前端挣得更多了,坏笑三联...

后端控制权限还是前端控制权限

前后端分离前后端就有了很多争论,比如分页后端做还是前端做要争论?信息检索是后端做还是前端做?最有名的就是权限之争,web的权限管理无非就是管理用户是否有访问某条url的权限,接口不用说得后端控制,但将路由交给前端之后,这就有了分歧,到底是前端做权限控制,还是后端,那作为一个后端苦逼码农,我是比较倾向于后端,因为更加可控,好维护,搞个动态路由就好了,有权限给菜单,没权限不给菜单,一切问题迎刃而解。

vue动态路由实现步骤

1、先在router中配置好无需权限控制的静态路由

import { createRouter, createWebHistory } from 'vue-router'

// 静态路由
const systemRouter = [
  {
    path: '/',
    name: 'Layout',
    component: () => import('../layout/index.vue'),
    redirect: '/dashboard',
    children: []
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/login/index.vue'),
    meta: {
      title: '登录'
    }
  },
  { 
    // 这里很奇怪动态路由不要加name属性,否则第一次就会跳转到404
    path: '/:pathMatch(.*)*',
    component: () => import('../layout/other/NotFound.vue')
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: systemRouter
})

// 路由前置守卫
router.beforeEach(async (to, from) => {

    // 动态路由在这里实现
})

以上代码是router中最基础的一个代码,动态路由我们当然是需要在导航守卫中去实现动态挂载。

假如,后端给我们返回的路由格式如下,我们将这些动态路由全部挂载到Layout,也就是首页路由的cheldren当中去。

const apiroutes = [
  {
    path: '/home',
    name: 'Home',
    meta: {
      title: '主页'
    },
    children: [
      {
        path: '/dashboard',
        name: 'Dashboard',
        component: 'home',
        meta: {
          title: '仪表板',
        }
      },
      {
        path: '/user',
        name: 'User',
        component: 'user',
        meta: {
          title: '个人信息',
        }
      }
    ]
  }
]

假如,后端给我们返回的路由结构如上所示,我们该如何动态挂载呢!

扁平化路由结构

// 扁平化数组对象
function flatten(arr) {
  return arr.reduce((result, item) => {
    return result.concat(item, Array.isArray(item.children) ? flatten(item.children) : [])
  }, [])
}

动态获取当前路由的组件信息,根据自己的情况修改,这段代码有点小bug,使用的时候需要自行优化一下,to为当前访问的路由信息, permmenus则是后端的apirouts

// 动态获取当前路由的组件信息
function generateRoute(to, permmenus) {
  let item = {}
  flatten(permmenus).forEach((element) => {
    if (element.path == to.path && element.component !== undefined) {
      item['path'] = element.path
      item['name'] = element.name
      item['component'] = element.component ? loadComponent(element.component) : () => import("../layout/other/Empty.vue")
      item['meta'] = element.meta
    }
  })
  return item
}

使用vite工具动态导包

// 动态导入组件
const modules = import.meta.glob('@/views/**/index.vue')
function loadComponent(component){
  return () => modules[`/src/views/${component}/index.vue`]()
}

最后,在路由的导航守卫中,动态挂载添加路由即可!vuerouter4通过hasRoute()方法判断路由是否挂载,addRoute()逐个挂载,这个代码还有优化的空间。

// 路由前置守卫
router.beforeEach(async (to, from) => {
 
  // 判断当前路由是否已加载,没有则去动态路由中匹配,未匹配到则跳转404
  if (!router.hasRoute(to.name) && JSON.stringify(generateRoute(to, authStore.getPermMenus)) !== '{}') {
    router.addRoute('Layout', generateRoute(to, apiroutes))
    return to.fullPath
  }
  return true
})

基本的动态思路就是这样,但有一个问题是,如果默认登录之后跳转的路由在动态路由当中,那么再跳转之前还未挂载到路由,终端可能会有黄色警告信息,两种解决办法,一种是在跳转之前先动态的将该路由挂载进去,或者直接将首页默认路由定义在静态路由当中,初始化的时候就挂载就不会有警告信息,我在参阅很多开源项目的时候,发现他们都存在该问题!我选择的是在跳转之前动态挂载!

你可能感兴趣的:(vue.js,前端,javascript)