vue3+vue-router+vite 实现动态路由
文章中出现的代码是演示版本,仅供参考,实际的业务需求会更加复杂
什么是动态路由
什么场景会用到动态路由
举一个最常见的例子,比如说我们要开发一个后台管理系统,一般来说后台管理系统都会分角色登录,这个时候也就涉及到了权限,比如说这个后台管理系统现在有超级管理员,管理员,运维,财务等
这几个角色,每个角色登录系统之后都会有不同的权限,超级管理员需要所有的权限,财务可能只需要财务相关的模块(菜单)以及按钮等,通常实现这种需求会有以下常见方案
路由表由前端去维护
也就是说我们已知这几个角色分别对应哪些权限,前端写好路由配置表,,后端只需要告诉你当前登录人是属于哪个角色,前端根据角色类型去写一个过滤函数,获取该角色所拥有的菜单以及按钮,然后动态的去添加路由,这样做有一个缺点就是,如果又增加了一个新的角色怎么办?某个角色想增加一些权限怎么办?这个时候前端就需要去新增或者修改代码,一点也不友好
路由表的数据由后端返回
这种也是常用的一种方式,可能我们的系统里面需要开发一些功能,如菜单管理
,角色管理
,用户管理
等,也就是常说的权限中心,前端开发完的页面所对应的路由信息有后端去维护,这个时候我们在开发的时候需要约束某一种规则,比如所有页面都放到/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`去获取valueconst 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类型,比如分为模块,菜单,页面,按钮等,到时候结合业务去实现逻辑
导航守卫使用时的注意事项,否则会出现刷新白屏,或者路由访问死循环等
相关文章:

vue3+vue-router+vite 实现动态路由
文章中出现的代码是演示版本,仅供参考,实际的业务需求会更加复杂 什么是动态路由 什么场景会用到动态路由 举一个最常见的例子,比如说我们要开发一个后台管理系统,一般来说后台管理系统都会分角色登录,这个时候也就涉…...

Okhttp hostnameVerifier详解
hostnameVerifier 方法简介核心原理参考资料 方法简介 本篇博文以Okhttp 4.6.0来解析hostnameVerfier的作用,顾名思义,该方法的主要作用就是鉴定hostnname的合法性。Okhttp在初始化的时候我们可以自己配置hostnameVerfier: new OkHttpClien…...

TCP的p2p网络模式
TCP的p2p网络模式 1、tcp连接的状态有以下11种 CLOSED:关闭状态LISTEN:服务端状态,等待客户端发起连接请求SYN_SENT:客户端已发送同步连接请求,等待服务端相应SYN_RECEIVED:服务器收到客户端的SYN请请求&…...
力扣-贪心算法4
406.根据身高重建队列 406. 根据身高重建队列 题目 假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或…...
动手学深度学习6.2 图像卷积-笔记练习(PyTorch)
以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。 本节课程地址:卷积层_哔哩哔哩_bilibili 代码_哔哩哔哩_bilibili 本节教材地址:6.2. 图像卷积 — 动…...

展开说说:Android服务之bindService解析
前面两篇文章我们分别总结了Android四种Service的基本使用以及源码层面总结一下startService的执行过程,本篇继续从源码层面总结bindService的执行过程。 本文依然按着是什么?有什么?怎么用?啥原理?的步骤来分析。 b…...

node-sass 老版本4.14.0 安装失败解决办法
旧项目 npm install 发现 node-sass 安装 失败 切换淘宝镜像之后 不能完全解决问题。因为需要编译,本地没有Python环境不能实现 安装node-sass时,在install阶段会从Github上下载一个叫binding.node的文件,而「GitHub Releases」里的文件…...

最近很火的字幕截图生成器
网址 https://disksing.com/fake-screenshot/ 最近很火的字幕截图生成器,对于自媒体来说真的太实用了 另外透露一下,你仔细研究就会发现,这是个纯前端的项目...

使用RabbitMQ实现可靠的消息传递机制
使用RabbitMQ实现可靠的消息传递机制 大家好,我是微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 1. RabbitMQ简介 RabbitMQ是一个开源的消息代理软件,实现了高级消息队列协议(AMQP&…...

Function Call ReACT,Agent应用落地的加速器_qwen的function calling和react有什么不同
探索智能体Agent的未来之路:Function Call与ReACT框架的较量,谁能引领未来? 引言 各大平台出现智能体应用创建,智能体逐渐落地,背后的使用哪种框架? 随着各大平台,例如百度千帆APPbuilder、阿…...

Java的JSONPath(fastjson)使用总结
背景 最近使用json实现复杂业务配置, 因为功能需要解析读取json的中节点数据。如果使用循环或者stream处理,可以实现,但是都过于麻烦。在想能否使用更简单json读取方式,正好发现fastjson支持该功能,本文做一个记录 案例说明 示…...

【大模型】大语言模型:光鲜背后的阴影——事实准确性和推理能力的挑战
大语言模型:光鲜背后的阴影——事实准确性和推理能力的挑战 引言一、概念界定二、事实准确性的局限2.1 训练数据的偏差2.2 知识的时效性问题2.3 复杂概念的理解与表述 三、推理能力的局限3.1 表层理解与深层逻辑的脱节3.2 缺乏常识推理3.3 无法进行长期记忆和连续推…...

Java面向对象练习(1.手机类)(2024.7.4)
手机类 package Phone;public class Phone {private String brand;private int price;private String color;public Phone(){}public Phone(String brand, int price, String color){this.brand brand;this.price price;this.color color;}public void setBrand(String bra…...

智慧生活新篇章,Vatee万腾平台领航前行
在21世纪的科技浪潮中,智慧生活已不再是一个遥远的梦想,而是正逐步成为我们日常生活的现实。从智能家居的温馨便捷,到智慧城市的高效运转,科技的每一次进步都在为我们的生活增添新的色彩。而在这场智慧生活的变革中,Va…...

Spring Cloud Gateway报sun.misc.Unsafe.park(Native Method)
项目引入spring cloud gateway的jar报,启动的时候报: [2024-07-05 10:10:16.162][main][ERROR][org.springframework.boot.web.embedded.tomcat.TomcatStarter][61]:Error starting Tomcat context. Exception: org.springframework.beans.factory.Bean…...

select single , select endselect
select single , select endselect single 根据条件找到一条数据,就出来了。 select endselect是在里面循环,每次找一条,依次放到into table中,或者放到into work area中,下面append table 。 实际开发中不建议这么操…...

后端学习(一)
添加数据库包: 数据库连接时 发生错误: 解决方式: SqlConnection conn new SqlConnection("serverlocalhost;databaseMyBBSDb;uidsa;pwd123456;Encryptfalse;") ;conn.Open();SqlCommand cmd new SqlCommand("SELECT * FROM…...

【活动行】参与上海两场线下活动,教育生态行业赛总决赛活动和WAIC人工智能大会活动 - 上海活动总结
目录 背景决赛最后一公里领域范围 决赛作品AI智教相机辅导老师Copilot辅导老师Copilot雅思写作竞技场 优秀作品总结 背景 决赛 百度发起的千帆杯教育生态行业赛于2024年7月4日进行线下决赛,博主虽然没能进入决赛,但也非常荣幸能够以嘉宾身份到现场给进…...

conda 安装设置
安装anaconda 推荐官网下载和安装,最新版本是anaconda3+python3.11,个人选择。有可能找不到 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror Tips:小白一定要全部勾选,特别第二项“add anaconda3 to my path environment variable…...

用PlantUML和语雀画UML类图
概述 首先阐述一下几个简单概念: UML:是统一建模语言(Unified Modeling Language)的缩写,它是一种用于软件工程的标准化建模语言,旨在提供一种通用的方式来可视化软件系统的结构、行为和交互。UML由Grady…...

uniapp微信小程序电子签名
先上效果图,不满意可以直接关闭这页签 新建成单独的组件,然后具体功能引入,具体功能点击签名按钮,把当前功能页面用样式隐藏掉,v-show和v-if也行,然后再把这个组件显示出来。 【签名-撤销】原理是之前绘画时…...

MetaPoint_速读
Meta-Point Learning and Refining for Category-Agnostic Pose Estimation https://arxiv.org/abs/2404.14808https://github.com/chenbys/metapointabstract 这篇文章介绍了一种名为Meta-Point Learning and Refining的框架,用于实现类别不可知的姿势估计。该框…...

数据库逆向工程工具reverse_sql
reverse_sql 是一个用于解析和转换 MySQL 二进制日志(binlog)的工具。它可以将二进制日志文件中记录的数据库更改操作(如插入、更新、删除)转换为反向的 SQL 语句,以便对系统或人为产生的误操作进行数据回滚和恢复。 *…...

四大内网穿透利器对比
本文精选四款市场上的佼佼者——巴比达、花生壳、Frp及NatApp,详细剖析它们的特点与优势,助力企业和个人用户精准选择,其中特别强调了巴比达在企业级安全访问方面的突出贡献。 1. 巴比达 特点 深度安全防护:巴比达提供全方位安…...

【LeetCode】每日一题:跳跃游戏 II
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最小…...

SpringBoot拦截器
目录 一、拦截器快速入门 (1)什么是拦截器 (2)拦截器的使用步骤 1、定义拦截器 🍀preHandle() 方法 🍀postHandle() 方法 🍀afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…...

uniapp中实现跳转链接到游览器(安卓-h5)
uniapp中实现跳转链接到游览器(安卓-h5) 项目中需要做到跳转到外部链接,网上找了很多都不是很符合自己的要求,需要编译成app后是跳转到游览器打开链接,编译成web是在新窗口打开链接。实现的代码如下: 效果&…...

WPF UI 界面布局 魔术棒 文字笔记识别 技能提升 布局功能扩展与自定义 继承Panel的对象,测量与排列 系列七
应用开发第一步 功能分类:页面上的功能区域划分。。。。需求分析 业务逻辑 数据流 功能模块 UI/UX 编码 测试 发布 功能开发与布局 不用显式的方式设定元素的尺寸 不使用屏幕坐标来指定位置 Grid 功能最强大,布局最灵活的容器…...

文件格式是.pb应该怎么查看?
文件格式为.pb的文件,通常是Google Protocol Buffers(简称PB)序列化后的二进制文件。要查看.pb文件的内容,可以采用以下方法: 1. **直接打开(不推荐)**: - 直接打开.pb文件通常会显示…...

android2024 gradle8 Processor和ksp两种编译时注解实现
android编译时注解,老生常谈,外面的例子都是bindView,脑壳看疼了,自己学习和编写下。 而且现在已经进化到kotlin2.0,google也逐渐放弃kapt,进入维护状态。所以要好好看看本贴。 参考我的工程: h…...