Vue3中简单实现动态添加路由

 更新时间:2023年05月31日 11:08:41   作者:bald3r  
本文主要介绍了Vue3中简单实现动态添加路由,,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

通过后端接口的返回值,动态添加路由,是作为权限控制的一种常见方式,本文将简单讲解如何在Vue3中动态添加路由。

示例数据

[
  {
    "id": 1,
    "pid": 0,
    "url": "/dashboard",
    "title": "控制面板板",
    "component": "/src/views/dashboard/DashboardView.vue",
    "icon": "SlidersOutlined",
    "is_show": 0,
    "level": 1,
    "sort": 1,
    "order": "1",
    "type": "menu",
    "status": 0,
    "children": null
  },
  {
    "id": 2,
    "pid": 0,
    "url": "/system",
    "title": "系统设置",
    "component": null,
    "icon": "ToolOutlined",
    "is_show": 0,
    "level": 1,
    "sort": 7,
    "order": "2",
    "type": "menu_dir",
    "tips": null,
    "status": 0,
    "children": [
      {
        "id": 7,
        "pid": 2,
        "url": "/system/menu",
        "title": "菜单管理",
        "component": "/src/views/system/MenuView.vue",
        "icon": "BarsOutlined",
        "is_show": 0,
        "level": 2,
        "sort": 3,
        "order": "2,7",
        "type": "menu",
        "tips": null,
        "status": 0,
        "children": [
          {
            "id": 8,
            "pid": 7,
            "url": "/system/menu/add",
            "title": "新增菜单",
            "component": null,
            "icon": null,
            "is_show": 1,
            "level": 3,
            "sort": 1,
            "order": "2,7,8",
            "type": "button",
            "tips": null,
            "status": 0,
            "children": null
          }
        ]
      }
    ]
  },
]

思路分析

动态添加路由的实质,就是先将后端返回的json数据转化成一个个RouteRecordRaw形式的对象,然后调用Vue Router的addRoute方法,添加进路由列表中。由于每个路由地址都会对应一个Vue组件,因此还需要将Vue组件都通过import.meta.glob读取到内存中。

具体实现函数

const viewsComponent: Record<string, any> = import.meta.glob("/src/views/**/*.vue", { eager: true })
const addRouteAll = (menu: RoleMenu[]) => {  //RoleMenu就是接口返回的数据的类型
    menu.forEach(item => {
        if (item.type === "menu" && viewsComponent[item.component]) {
            addRouteItem(item)
        }
        if (item.children && item.children.length > 0) {
            addRouteAll(item.children)
        }
    })
}
const addRouteItem = (route: RoleMenu) => {
    const path = route.url
    const component = viewsComponent[route.component]
    const routeBaseInfo: RouteRecordRaw = {
        path,
        name: path.substring(1),
        component: component.default,
        meta: {
            title: route.title,
            icon: route.icon,
            keepalive: route.children && route.children.length > 0 ? 0 : path.substring(1),
            menu_type: "tab",
            type: route.type,
            url: route.url,
            addTab: true
        }
    }
    router.addRoute(routeBaseInfo)
}

存在问题

路由何时处理?

笔者一开始认为,登录成功后立刻调用获取菜单的接口,然后处理路由,因此路由的处理应该在登录页面中的登录请求成功后进行处理,但是此时存在一个问题,用户登录成功进入后台页面,然后用户刷新页面,就会提示导航失败,控制台也会报错,因此笔者认为应该在登录成功进入后台页面之后开始处理。

笔者后台的主体页面框架为MainLayout,因此笔者在此进行路由处理。

const getMenu = () => {
    apiAuthMenuList().then(res => {
        menuList.value = handleMenu(res.content)  //菜单处理
        addRouteAll(res.content)
    })
}
onMounted(() => {
    getMenu()
})

导航失败

⚠️ [Vue Router warn] : No match found for location with path "/dashboard"

这是因为路由跳转的时机要早于组件挂载,因此在组件挂载并处理路由前,路由就已经跳转并报错了。

笔者解决这个问题的思路有两个:

  • 首先定义全局变量routeReady,初始值为false,当路由处理完成后变为true
  • 在路由守卫beforeEach中判断,如果routeReadyfalse则处理路由,处理完成后跳转。
  • 创建一个Loading页面,如果路由没有匹配的地址则跳转至Loading页面,并在该页面进行判断:
    • 如果routeReadytrue,说明去往的地址并不在该用户的权限菜单中,转向404页面
    • 如果routeReadyfalse,则说明路由未加载完成,那么就在当前页面等待,等routeReadytrue时,再执行上面的判断

笔者这里用了方法2。

//截获所有未匹配的路由,进入Loading页面
{
    path: "/:pathMatch(.*)*",
    component: () => import("../views/LoadingView.vue")
}
//LoadingView.vue
watchEffect(() => {
    if (globalStore.routeReady) {
        const routeList = router.getRoutes()
        if (routeList.find(i => i.path === router.currentRoute.value.fullPath)) {
            router.push(router.currentRoute.value.fullPath)
        } else {
            router.push("/notFound")
        }
    }
})

通过这种方式,可以在用户刷新页面后有一个顺滑的体验。

进入第一个路由

目前还存在一个问题,用户在登录跳转后,会进入后台页面,但是此时不会进入到任一菜单中:

而我们希望登录跳转后能自动进入到第一个菜单,即:

因此我们需要一个方法来找到第一个可用的路由:

const getFirstRoute = (routes: RouteRecordRaw[]): false | RouteRecordRaw => {
    const routerPaths: string[] = []
    const routers = router.getRoutes()
    routers.forEach(item => {
        if (item.path) routerPaths.push(item.path)
    })
    let find: boolean | RouteRecordRaw = false
    for (const key in routes) {
        if (routes[key].meta?.type != "menu_dir" && routerPaths.indexOf(routes[key].path) !== -1) {
            return routes[key]
        } else if (routes[key].children && routes[key].children?.length) {
            find = getFirstRoute(routes[key].children!)
            if (find) return find
        }
    }
    return find
}

然后调用这个方法即可:

const init = () => {
    const firstRoute = getFirstRoute(menuList.value!)
    if (firstRoute) {
        router.push(firstRoute.path)
    }
}
onMounted(() => {
    init()
})

后记

到此这篇关于Vue3中简单实现动态添加路由的文章就介绍到这了,更多相关Vue3动态添加路由内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 说说如何在Vue.js中实现数字输入组件的方法

    说说如何在Vue.js中实现数字输入组件的方法

    这篇文章主要介绍了说说如何在Vue.js中实现数字输入组件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • Vue项目中使用iView组件库设置样式不生效的解决方案

    Vue项目中使用iView组件库设置样式不生效的解决方案

    这篇文章主要介绍了Vue项目中使用iView组件库设置样式不生效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue中ant-design-vue组件的安装与使用

    vue中ant-design-vue组件的安装与使用

    Ant Design Vue是使用Vue实现的遵循Ant Design设计规范的高质量UI组件库,用于开发和服务于企业级中后台产品,下面这篇文章主要给大家介绍了关于vue中ant-design-vue组件安装与使用的相关资料,需要的朋友可以参考下
    2022-04-04
  • 解决Vue中 父子传值 数据丢失问题

    解决Vue中 父子传值 数据丢失问题

    这篇文章主要介绍了解决Vue中 父子传值 数据丢失问题,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • vue选项卡Tabs组件实现示例详解

    vue选项卡Tabs组件实现示例详解

    这篇文章主要为大家介绍了vue选项卡Tabs组件实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 解决vue2.x中数据渲染以及vuex缓存的问题

    解决vue2.x中数据渲染以及vuex缓存的问题

    本篇文章主要介绍了vue2.x中请求之前数据显示以及vuex缓存的问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • 深入理解Vue-cli4路由配置

    深入理解Vue-cli4路由配置

    Vue-router是Vue官方的路由插件,本文将结合实例代码,介绍Vue-cli4路由配置,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • vue路由组件路径如何用变量形式动态引入

    vue路由组件路径如何用变量形式动态引入

    这篇文章主要介绍了vue路由组件路径如何用变量形式动态引入问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • vue中$set的使用(结合在实际应用中遇到的坑)

    vue中$set的使用(结合在实际应用中遇到的坑)

    这篇文章主要介绍了vue中$set的使用(结合在实际应用中遇到的坑),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 深入理解 Vue 3实现组件通信的方法

    深入理解 Vue 3实现组件通信的方法

    本文将介绍几种常见的 Vue 3 组件通信方法,包括 props、emits、provide 和 inject、事件总线以及 Vuex 状态管理,需要的朋友可以参考下
    2024-07-07

最新评论