vue3+vue-router+vite 实现动态路由

news2024/11/25 20:41:07

文章中出现的代码是演示版本,仅供参考,实际的业务需求会更加复杂

什么是动态路由

在这里插入图片描述

什么场景会用到动态路由

举一个最常见的例子,比如说我们要开发一个后台管理系统,一般来说后台管理系统都会分角色登录,这个时候也就涉及到了权限,比如说这个后台管理系统现在有超级管理员,管理员,运维,财务等这几个角色,每个角色登录系统之后都会有不同的权限,超级管理员需要所有的权限,财务可能只需要财务相关的模块(菜单)以及按钮等,通常实现这种需求会有以下常见方案

路由表由前端去维护

也就是说我们已知这几个角色分别对应哪些权限,前端写好路由配置表,,后端只需要告诉你当前登录人是属于哪个角色,前端根据角色类型去写一个过滤函数,获取该角色所拥有的菜单以及按钮,然后动态的去添加路由,这样做有一个缺点就是,如果又增加了一个新的角色怎么办?某个角色想增加一些权限怎么办?这个时候前端就需要去新增或者修改代码,一点也不友好

路由表的数据由后端返回

这种也是常用的一种方式,可能我们的系统里面需要开发一些功能,如菜单管理,角色管理,用户管理等,也就是常说的权限中心,前端开发完的页面所对应的路由信息有后端去维护,这个时候我们在开发的时候需要约束某一种规则,比如所有页面都放到/src/views目标下面,然后通过菜单管理去维护数据,维护完的数据可以到角色管理里面去配置角色菜单,配置完角色,可以到用户管理里面给某个用户配置角色等一些列流程,这样的话即使新增一个角色,或者修改一个角色的角色菜单,前端都不需要去修改代码,只要在菜单管理里面维护好了数据,想怎么改怎么改,后端返回的数据格式可能如下:

[
  {
    path: "/application",
    name: "application",
    component: "Layout",
    title: "应用管理",
    show: true,
    icon: "",
    children: [
      {
        path: "",
        name: "application-index",
        component: "/application/index.vue",
      },
    ],
  },
  {
    path: "/permission",
    name: "permission",
    component: "Layout",
    title: "权限管理",
    show: true,
    icon: "",
    children: [
      {
        path: "menu",
        name: "permission-menu",
        component: "/permission/menu/index.vue",
        title: "菜单管理",
        show: true,
        icon: "",
      },
      {
        path: "user",
        name: "permission-user",
        component: "/permission/user/index.vue",
        title: "用户管理",
        show: true,
        icon: "",
      },
      {
        path: "role",
        name: "permission-role",
        component: "/permission/role/index.vue",
        title: "角色管理",
        show: true,
        icon: "",
      },
    ],
  },
]

其实仔细观察这个数据结构,是不是有点熟悉,path,name,component,children,我们好像手动维护路由表的时候也会用到这些属性

如何实现动态路由

实现动态路由其实就要用到vue-router提供的一个方法,叫addRoute在之前版本的时候是addRoutes,现在非版本的vue-router给废除了
addRoute()如何使用呢?可以看一下官方文档

当我们添加一个主路由的时候

router.addRoute({ path: '/permission', name: 'permission', component: () => import('xxxxx')})

添加子路由也就是嵌套路由

router.addRoute('主路由的name', { path: 'settings', component: AdminSettings })

在这里插入图片描述
既然我们已经知道了addRoute()方法如何使用,下面我们就可以去实现这部分逻辑
我们看一下官方文档的导航守卫里面的内容
在这里插入图片描述
在这里插入图片描述
在之前我们使用导航守卫的时候需要一个参数next()去控制是否放行以及去哪个页面,但是在新版本的vue-router里面可以不是用next(),当然你是用也行~

我们可以新建一个permission.ts文件

import router from "./index";
import { useSessionStorage } from "@vueuse/core";
import { StorageEnum } from "@/enum";
import { useUserStore } from "@/store";

const whiteList = ["/login", "/404"];

router.beforeEach(async (to) => {
  const token = useSessionStorage(StorageEnum.TOKEN, "").value;
  // 如果在白名单里面 并且 token 不存在
  if (whiteList.includes(to.path) && !token) {
    return true;
  } else {
    const { menuList, getMenuList } = useUserStore();
    // 如果为空数组,name就请求接口重新获取后端维护的路由数据
    if (!menuList.length) {
      await getMenuList();

      console.log("获取全部路由 =>", router.getRoutes());
      // 触发重定向 不这样写会导致刷新找不到路由 两种写法都行
      // return { path: to.fullPath };
      return to.fullPath;
    }
  }
});

这里我们可以看到一会return true一会return to.fullpath是为什么,通过官方导航守卫里面的介绍,我们可以知道的是
在这里插入图片描述
通过官方文档动态路由,我们可以直到
在这里插入图片描述
所以说return to.fullpath是官方告诉我们要这么使用,也是为了解决动态路由页面刷新的时候会出现页面空白或者404的问题
出现404的话比如说你在路由表中维护了下面路由映射

{
 path: "/:pathMatch(.*)",
  name: "page404",
  component: () => import("@/views/system/404.vue"),
}

上面说的主要是在全局导航守卫里面的一些使用及注意事项,我们可以看到并没有用到addRoute()这个方法,也没有出现拿到后端数据前端转换成路由表的相关代码,但是我们可以看到有一个getMenuList()函数,我们在开发的时候,肯定是要考虑到复用以及复杂逻辑抽取的问题,一个动态路由的实现会牵扯到很多知识点接口请求,vuex或者pinia状态维护,vue-router,vite里面怎么获取文件等
下面看一下如何获取到接口给的数据,转换成vue-router能够识别的数据
首先我们要看一个vite官方给提供的功能,我们拿到后端给的文件路径如上面代码出现的component字段,如/application/index.vue,这个文件可能在我们本地项目中的src/views/application/index.vue这个路径下
在这里插入图片描述
我们需要把它转换成一个下面的格式() => import('xxxx'),我们需要动态的去拼接获取文件,该怎么实现呢?
vite官方文档中有说明
在这里插入图片描述
需要使用import.meta.glob,这个时候我们可以打印一下import.meta.glob("../views/**"),看一下返回的到底是什么
在这里插入图片描述
返回的是一个对象,而对象的key我们可以拼接获取到,而value正是我们想要的动态获取的文件路径
以下代码仅供参考,有很多需要完善的地方,只为演示使用

import type { RouterType } from "@/router/type";
import router from "@/router";
import type { RouteRecordRaw } from "vue-router";

export const useRouterConfig = () => {
	// 获取views目录下的所有的文件 不要使用@别名 
  const modules = import.meta.glob("../views/**");
  const asyncRoutes = ref<RouterType[]>([]);

  const addRoutes = (menus: RouterType[]) => {
    asyncRoutes.value = menus;
    filterAsyncRouter();
    // 动态添加 / 路由
    router.addRoute({
      path: "/",
      redirect: asyncRoutes.value[0].path,
    });
  };

  const filterAsyncRouter = () => {
    const routerLoop = (routes: RouterType[], ParentName?: string) => {
      routes.forEach((item) => {
        if (item.component === "Layout") {
          item.component = () => import("@/layout/index.vue");
        } else {
          item.component = resolveComponent(item.component);
        }
        const { title, show, icon, name, path, component, children } = item;
        const route: RouteRecordRaw = {
          component,
          path,
          name,
          meta: {
            title,
            show,
            icon,
          },
          children: children as any,
        };
		
		// 动态添加路由
        if (ParentName) {
          router.addRoute(ParentName, route);
        } else {
          router.addRoute(route);
        }

        if (item.children && item.children.length > 0) {
          routerLoop(item.children, item.name);
        }
      });
    };

    routerLoop(asyncRoutes.value);
  };

  const resolveComponent = (path: string) => {
    console.log(modules);
    // 拿到views下面的所有文件之后,动态拼接`key`去获取value
    const importPage = modules[`../views${path}`];
    if (!importPage) {
      throw new Error(
        `Unknown page ${path}. Is it located under Pages with a .vue extension?`
      );
    }
    return importPage;
  };

  return { addRoutes };
};

综上所述:

要想实现vite+vue-router实现动态路由我们需要用到

  • addRoute()
  • import.meta.glob()
  • 获取后端tree数据,递归循环,可能业务会有type类型,比如分为模块,菜单,页面,按钮等,到时候结合业务去实现逻辑
  • 导航守卫使用时的注意事项,否则会出现刷新白屏,或者路由访问死循环等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1892876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

幻兽帕鲁卡顿严重、延迟高怎么办?幻兽帕鲁卡顿问题处理

幻兽帕鲁更是一款支持多人游戏模式的生存制作游戏。玩家们可以邀请好友一同加入这个充满奇幻与冒险的世界&#xff0c;共同挑战强大的敌人&#xff0c;分享胜利的喜悦。在多人模式中&#xff0c;玩家之间的合作与竞争将成为游戏的一大看点。玩家们需要充分发挥自己的智慧和策略…

centos7的yum命令无法使用解决方案

文章目录 问题排查流程解决方案总结 问题 今天新建了个centos7的虚拟机发现yum无法正常使用 已加载插件&#xff1a;fastestmirror Determining fastest mirrors Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archx86_64&repoos&infra…

单片机学习(14)--DS18B20温度传感器

DS18B20温度传感器 13.1DS18B20温度传感器基础知识1.DS18B20介绍2.引脚及应用电路3.内部结构框图4.存储器框图5.单总线介绍6.单总线电路规范7.单总线时序结构8.DS18B20操作流程9.DS18B20数据帧 13.2DS18B20温度读取和温度报警器代码1.DS18B20温度读取&#xff08;1&#xff09;…

linux模拟aix盘19c单机asm安装补丁

linux模拟盘aix盘vi /etc/rc.d/rc.local/bin/ln /dev/sda /dev/rhdisk2/bin/ln /dev/sdb /dev/rhdisk3 /bin/chown grid:oinstall /dev/rhdisk*chmod 660 /dev/rhdisk* 一、19c安装GI&#xff08;Standalone Oracle Restart&#xff09; su - grid配置环境变量vi .profileex…

【Linux】Linux用户,用户组,其他人

1.文件拥有者 初次接触Linux的朋友大概会觉得很怪异&#xff0c;怎么“Linux有这么多用户&#xff0c;还分什么用户组&#xff0c;有什用呢&#xff1f;”&#xff0c;这个“用户与用户组”的功能可是相当健全而且好用的一个安全防护措施。 怎么说呢&#xff1f;由于Linux是个…

人生感悟 | 努力奋斗和内卷不是一个意思。

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 有个很有趣的话题&#xff0c;是不是努力奋斗导致的内卷&#xff1f; 如果每个人都躺平&#xff0c;各行各业的内卷是不是就不存在了&#xff1f; 01 有关联不尽同 两者有关量&#xff0c;但无绝对的导向关系。 努力…

vue高德地图使用

先根据官方方法给vue项目引入高德 高德文档地址 做好准备后使用 初始化地图 AMap.plugin(AMap.MoveAnimation, () >{//地图this.map new AMap.Map("mapContainer", {resizeEnable: true,center: [116.397447,39.909176],//地图中心坐标zoom:12,//缩放值});this.…

掌握亚马逊自养号:测评策略的核心要点与实战经验

在当今电商领域的激烈角逐中&#xff0c;亚马逊测评对于卖家而言&#xff0c;已从单纯的销量助推器与好评累积工具&#xff0c;进化为品牌塑造与市场洞察的关键环节。然而&#xff0c;许多卖家仍局限于传统认知&#xff0c;未能充分挖掘自养号测评的多元化价值与深远影响。本文…

深入Kafka:如何保证数据一致性与可靠性?

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! Hello, 大家好!我是小米,今天我们来聊一聊Kafka的一致性问题。Kafka作为一个高性能的分布式流处理平台,一直以来都备受关注。今天,我将深入探讨Kaf…

智算中心风云再起,如何锚定突围之路?

导读&#xff1a;2024年&#xff0c;智算中心建设全面提速&#xff0c;头部玩家争相布局。如何打造智算中心的差异化竞争能力&#xff1f; 2024年&#xff0c;随着大模型和生成式AI应用加速落地&#xff0c;各行各业对AI算力的需求持续暴涨。作为AI时代的算力基础设施&#xff…

Spring AI 1.0.0 新变化,从 0.8.1 如何升级

Spring AI 1.0.0-M1 版本已经发布&#xff0c;距离 1.0.0 正式版又更近了一步。同时这也意味着&#xff0c;Spring AI 1.0.0 的 API 已经基本确定&#xff0c;不会发生大的改动。这里介绍一下&#xff0c;相对于上一个发布版本 0.8.1&#xff0c;Spring AI 1.0.0 的一些重要的变…

【pearcmd】通过pearcmd.php 进行GetShell

https://cloud.tencent.com/developer/article/2204400 关于PHP 配置 register_argc_argv 小结 的一些研究文章。 应用例题 [NewStarCTF 2023 公开赛道]Include &#x1f350; <?phperror_reporting(0);if(isset($_GET[file])) {$file $_GET[file];if(preg_match(/flag|l…

国外惊现IDM命令行永久破解方法

IDM 想必大部分人都知道和使用过&#xff0c;这是一款在国内外都非常流行的下载神器&#xff0c;除了不能支持种子文件和磁力之外&#xff0c;完爆国内的迅雷&#xff0c;小编我在 6 年前就已经购买了永久更新正版。 image.png 不过最近国外有大神流传出了一个号称可以永久完美…

如何在Docker容器中,修改MySQL密码

如果MySQL运行在Docker容器中&#xff0c;修改MySQL密码的方法稍有不同。以下是如何在Docker中修改MySQL密码的步骤&#xff1a; 方法1&#xff1a;使用MySQL命令行工具 1. 找到MySQL容器的ID或者名字&#xff1a; docker ps 2. 进入MySQL容器&#xff1a; docker exec -i…

Hi3861 OpenHarmony嵌入式应用入门--UDP Client

本篇使用的是lwip编写udp客户端。需要提前准备好一个PARAM_HOTSPOT_SSID宏定义的热点&#xff0c;并且密码为PARAM_HOTSPOT_PSK。还需要准备一个udp服务&#xff0c;服务ip为PARAM_SERVER_ADDR宏定义&#xff0c;端口为PARAM_SERVER_PORT宏定义。 修改网络参数 在Hi3861开发板…

如何挑选短剧系统源码?

在选择短剧系统源码之前&#xff0c;我们需要明确什么是短剧系统源码。短剧系统源码是指用于构建和管理短剧内容的程序代码。选择适合的短剧系统源码可以提高短剧制作的效率和质量。下面是几个选择短剧系统源码的建议&#xff1a; 需求分析&#xff1a;在选择短剧系统源码之前&…

【代码随想录】【算法训练营】【第58天】 [卡码101]孤岛的总面积 [卡码102]沉没孤岛 [卡码103]水流问题 [卡码104]建造最大岛屿

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 卡码网。 day 58&#xff0c;周四&#xff0c;ding~ 题目详情 [卡码101] 孤岛的总面积 题目描述 卡码101 孤岛的总面积 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语言 […

word 转pdf 中图片不被压缩的方法

word 转pdf 中图片不被压缩的方法 法1&#xff1a; 调节word 选项中的图片格式为不压缩、高保真 法2&#xff1a; 1: word 中的图片尽可能使用高的分辨率&#xff0c;图片存为pnd或者 tif 格式&#xff08;最高清&#xff09; 2: 转化为pdf使用打印机器&#xff0c;参数如下…

实验七 SQL数据更新和视图

题目 &#xff08;1&#xff09;向商品类别表category中插入一条记录&#xff08;801&#xff0c;‘座椅套’&#xff0c;‘各种品牌的汽车座套’&#xff09; &#xff08;2&#xff09;向商品表product中插入一条记录&#xff1a;商品编号80101&#xff0c;商品名称“四季通…

基于Springboot的人格障碍诊断系统

结构图&#xff1a; 效果图&#xff1a; 后台&#xff1a; 前台: