v3-admin-vite 改造自动路由,view页面自解释Meta
需求
v3-admin-vite是一款不错的后端管理模板,主要是pany一直都在维护,最近将后台管理也进行了升级,顺便完成一直没时间解决的小痛痒:
在不使用后端动态管理的情况下。我不希望单独维护一份路由定义,我希望页面是自解释的。就像HTML标记,一个页面的标题等信息由页面内<title>决定,而一个页面的访问地址(路由)由页面目录决定。很自然的思维是么?单独维护一份路由感觉就没那么自然了,我希望这一切都由页面自解释。访问路径我只需要移动页面的位置,Ctrl+CV目录的结构就好了
思路
之前实战过数个项目,大部分都轻车熟路了。但是对于v3-admin-vite系统,还是有几个地方需要调整 :
1.目录的定义
目录的定义除了名称外,还有图标等信息需要管理。因此需要采用文件补充信息,我的解决方案是将要输出成为左侧目录结构的目录(好绕口)下放一个index.ts文件,为了避免和其它的文件冲突,约定默认导出export default必须包含title这个string信息,表示目录名称(神马?title为空怎么办?有点正常业务思维吧),顺便把图标的定义也在导出解决。
2.View文件的定义
View文件的定义由于目录定义一样,只需要将你导出成为菜单的vue模块添加导出定义即可。把meta信息导出,自动输出路由配置。
3.Name约定
除了meta信息以外,admin-v3还要求name不能一致(没试过 ?改个一样的试试看😏),我们可以直接从文件名读取,至少一个目录下文件名是不会一致的。当然如果多个目录的话,就要注意一下了,功能页面名称唯一这个应该很容易办到。
4.递归扫描文件
webpack,vite等工具都提供了文件扫描的接口,只是不能使用变量进行路径扫描,必须字面量(常量),好在支持通配符。解决起来不难。
5.顺序问题的解决
由于工具扫描都是基于文件名称的,而实际需要显示的结构和文件顺序 不一定相同,例如我有a.vue,b.vue,按名称扫描a会出现在前面。因此我扩充了一下Meta定义,添加了一个position属性 ,没设置时,默认以100作为排序值,根据其对所有的目录递归排序,这样就OK了。
功能实现
看一下最终的对应效果
对于目录标记,我们只需要在目录下添加一个index.ts文件:
import { RouteMetaEx } from '@/router'export default {title: '二级目录测试',
} as RouteMetaEx
对于View模块,我们只需要添加多一个typescript块导出meta:
<template><div>测试节点3</div>
</template>
<script lang="ts">
import { RouteMetaEx } from '@/router'
const meta: RouteMetaEx = {title: '3级节点1', // 只有导出title的才会成为路由elIcon: 'Cpu', // element-ui的内置ICON,比svgIcon优先// svgIcon: 'dashboard',roles: ['role0'], // 哪些角色可以显示position: 100//keepAlive: true // 是否要keepAlive保持页面状态// hidden: true 默认为false,不会挂载到菜单
}
export default meta
</script>
使用是不很简单?哈哈哈哈。
这里添加了position的RouteMetaEx在后面有定义,其它结构和功能和Meta定义一致。注意vue的文件名在view下要唯一。
然后我们的src/router/index.ts里dynamicRoutes需要按照下面方式来导出:
export interface RouteMetaEx extends RouteMeta {position?: number //排序,不填写的话默认为100,用于控制菜单顺序
}/*** admin-vite-v3 自动路由* 递归扫描views下的文件,识别导出title的页面加入路由,需要配置权限 (Roles 属性)* 注意二级目录产生要求在目录index.ts里导出含title的meta* @author Jim 2024/4/1*/
const autoRoutes: Array<RouteRecordRaw> = []const scanDir: Record<string, any> = import.meta.glob('../views/**/index.ts', { eager: true }) // 处理目录
const dirNodeCache = new Map<string, RouteRecordRaw>()
for (const key in scanDir) {const component = scanDir[key]if (component.default?.title) {// 通过默认导出title判断const groups = /\.\.\/views\/((\w+\/)+)index\.ts/.exec(key) || []const dirName = groups[2].slice(0, -1) // 提取目录名const perfix = groups[1].slice(0, -dirName.length - 1) // 提取前缀目录const currentNode: RouteRecordRaw = {path: dirName,name: dirName,children: [],meta: { ...component.default, alwaysShow: true } // 合并alwaysShow进去,保持目录结构}const upperNode = dirNodeCache.get(perfix)if (upperNode) {upperNode.children?.push(currentNode)} else {// 一级目录currentNode.path = `/${dirName}` // 更改根格式currentNode.component = LayoutsautoRoutes.push(currentNode)}dirNodeCache.set(groups[1], currentNode)}
}
const scanModule: Record<string, any> = import.meta.glob('../views/**/*.vue', { eager: true }) // 处理节点
for (const key in scanModule) {const component = scanModule[key]if (component.default?.title) {// 通过默认导出title判断const groups = /\.\.\/views\/((\w+\/)*)(\w+)\.vue/.exec(key) || []const dirPath = groups[1]const moduleName = groups[3]if (!dirPath) {// 一级菜单特殊处理autoRoutes.push({path: `/${moduleName}`,name: moduleName,component: Layouts,redirect: `/${moduleName}/index`,meta: component.default,children: [{path: 'index',name: moduleName,component: () => component,meta: component.default}]})} else {const currentNode: RouteRecordRaw = {path: moduleName,name: moduleName,component: () => component,meta: component.default}const upperNode = dirNodeCache.get(dirPath)if (upperNode) {// 挂上级目录下,没有定义就不要挂了upperNode.children?.push(currentNode)} else {console.error(`upper node ${dirPath} not found`)}}}
}const sortFunc = (a: RouteRecordRaw, b: RouteRecordRaw) =>((a.meta as RouteMetaEx).position ?? 100) - ((b.meta as RouteMetaEx).position ?? 100)
function sortByPosition(nodes: RouteRecordRaw[]) {nodes.forEach((node: RouteRecordRaw) => {if (node.children) {const sortedChildren = node.children.sort(sortFunc) // 排序所有childrensortByPosition(sortedChildren)}})
}
autoRoutes.sort(sortFunc)
sortByPosition(autoRoutes)export const dynamicRoutes: RouteRecordRaw[] = autoRoutes
其他部分可以不用动。这样我们便有了路由导出的功能。
副作用
这样处理虽然开发方便,但是也有它的局限和副作用。副作用就是分包问题,由于所有的模块获取菜单定义必须读文件,因此无法懒加载,会导致扫描过程需要加载全部的模块,这样一来当模块非常多的时候加载会比较耗资源,也无法细化的分包。但对于中小项目一个gzip包全部load下来还是问题不大。大型项目可能要采用其它方案例如自动化脚本来输出路由。
相关文章:
v3-admin-vite 改造自动路由,view页面自解释Meta
需求 v3-admin-vite是一款不错的后端管理模板,主要是pany一直都在维护,最近将后台管理也进行了升级,顺便完成一直没时间解决的小痛痒: 在不使用后端动态管理的情况下。我不希望单独维护一份路由定义,我希望页面是自解…...
FIFO存储器选型参数,结构原理,工艺与注意问题总结
🏡《总目录》 目录 1,概述2.1,写入操作2.2,读取操作2.3,指针移动与循环2.4,状态检测3,结构特点3.1,双口RAM结构3.2,无外部读写地址线3.3,内部读写指针自动递增3.4,固定深度的缓冲区4,工艺流程4.1,硅晶圆准备...
jvm高级面试题-2024
说下对JVM内存模型的理解 JVM内存模型主要是指Java虚拟机在运行时所使用的内存结构。它主要包括堆、栈、方法区和程序计数器等部分。 堆是JVM中最大的一块内存区域,用于存储对象实例。一般通过new关键字创建的对象都存放在堆中,堆的大小可以通过启动参数…...
DeepL Pro3.1 下载地址及安装教程
DeepL Pro是DeepL公司推出的专业翻译服务。DeepL是一家专注于机器翻译和自然语言处理技术的公司,其翻译引擎被认为在质量和准确性方面表现优秀.DeepL Pro提供了一系列高级功能和服务,以满足专业用户的翻译需求。其中包括: 高质量翻译…...
第十一届 “MathorCup“- B题:基于机器学习的团簇能量预测及结构全局寻优方法
目录 摘 要 第 1 章 问题重述 1.1 问题背景 1.2 问题描述 第 2 章 思路分析...
云计算探索-如何在服务器上配置RAID(附模拟器)
一,引言 RAID(Redundant Array of Independent Disks)是一种将多个物理硬盘组合成一个逻辑单元的技术,旨在提升数据存取速度、增大存储容量以及提高数据可靠性。在服务器环境中配置RAID尤其重要,它不仅能够应对高并发访…...
LeetCode226:反转二叉树
题目描述 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 解题思想 使用前序遍历和后序遍历比较方便 代码 class Solution { public:TreeNode* invertTree(TreeNode* root) {if (root nullptr) return root;swap(root->left, root…...
特征融合篇 | 利用RT-DETR的AIFI去替换YOLOv8中的SPPF(附2种改进方法)
前言:Hello大家好,我是小哥谈。RT-DETR模型是一种用于目标检测的深度学习模型,它基于transformer架构,特别适用于实时处理序列数据。在RT-DETR模型中,AIFI(基于注意力的内部尺度特征交互)模块是一个关键组件,它通过引入注意力机制来增强模型对局部和全局信息的处理能力…...
MVCC多版本并发控制
1.什么是MVCC MVCC (Multiversion Concurrency Control),多版本并发控制。MySQL通过MVCC来实现隔离性。隔离性本质上是因为同时存在多个并发事务可能会导致脏读、幻读等情况。要解决并发问题只有一种方案就是加锁。当然,锁不可避免…...
图片转换成base64如何在html文件中使用呢
在HTML文件中使用Base64编码的图片非常简单。Base64编码是一种将二进制数据转换为ASCII字符串的方法,这使得可以直接在网页上嵌入图片数据,而无需引用外部图片文件。以下是如何在HTML中使用Base64编码的图片的步骤: 步骤 1: 将图片转换为Bas…...
【MATLAB源码-第24期】基于matlab的水声通信中海洋噪声的建模仿真,对比不同风速的影响。
操作环境: MATLAB 2022a 1、算法描述 水声通信: 水声通信是一种利用水中传播声波的方式进行信息传递的技术。它在水下环境中被广泛应用,特别是在海洋科学研究、海洋资源勘探、水下军事通信等领域。 1. **传输媒介**:水声通信利…...
七、函数的使用方法
函数的调用 nameinput()#输入参数并赋值name print(name)#d打印name 格式:返回值函数名(参数) def get_sum(n):#形式参数计算累加和:param n::return: sumsum0for i in range(1,n1):sumiprint…...
数据分析之Tebleau 简介、安装及数据导入
Tebleau简介 Tebleau基于斯坦福大学突破性交互式技术 可以将结构化数据快速生成图表、坐标图、仪表盘与报告 将维度拖放到画布等地方是他的主要操作方式 例:Tebleau是手机相机 (相对来说更简单) POWER BI是单反相机 Tebleau各类产品 Teblea…...
分享一下设计模式的学习
分享一下设计模式的学习 1、什么是设计模式? 设计模式是在软件设计过程中,经过实践和总结得出的描述、解决软件设计问题的一种经验总结。它是一种被广泛接受和验证的最佳实践,用于解决特定类型的问题,并提供了可重用的解决方案。…...
【JavaEE初阶系列】——CAS
目录 🎈什么是 CAS 📝CAS 伪代码 🎈CAS 是怎么实现的 🎈CAS 有哪些应用 🚩实现原子类 🌈伪代码实现: 🚩实现自旋锁 🌈自旋锁伪代码 🎈CAS 的 ABA 问题 &#…...
webGIS 之 智慧校园案例
1.引入资源创建地图 //index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&qu…...
CVAE——生成0-9数字图像(Pytorch+mnist)
1、简介 CVAE(Conditional Variational Autoencoder,条件变分自编码器)是一种变分自编码器(VAE)的变体,用于生成有条件的数据。在传统的变分自编码器中,生成的数据是完全由潜在变量决定的&…...
【Linux】TCP网络套接字编程+守护进程
文章目录 日志类(完成TCP/UDP套接字常见连接过程中的日志打印)单进程版本的服务器客户端通信多进程版本和多线程版本守护进程化的多线程服务器 日志类(完成TCP/UDP套接字常见连接过程中的日志打印) 为了让我们的代码更规范化&…...
【Qt 学习笔记】Day2 | 认识QtSDK中的重要工具
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Day2 | 认识QtSDK中的重要工具 文章编号:Qt 学习笔记 / 03…...
adc123456
DMA主要用于协助CPU完成数据转运的工作 DMA,英文全称Direct Memory Access,DMA这个外设是可以直接访问STM32内部存储器的,包括运行内存SRAM,程序存储器flash和寄存器等等,DMA都有权限访问,所以DMA能完成数据…...
YOLOV5训练自己的数据集教程(万字整理,实现0-1)
文章目录 一、YOLOV5下载地址 二、版本及配置说明 三、初步测试 四、制作自己的数据集及转txt格式 1、数据集要求 2、下载labelme 3、安装依赖库 4、labelme操作 五、.json转txt、.xml转txt 六、修改配置文件 1、coco128.yaml->ddjc_parameter.yaml 2、yolov5x.…...
精通Go语言文件上传:深入探讨r.FormFile函数的应用与优化
1. 介绍 1.1 概述 在 Web 开发中,文件上传是一项常见的功能需求,用于允许用户向服务器提交文件,如图像、文档、视频等。Go 语言作为一门强大的服务器端编程语言,提供了方便且高效的方式来处理文件上传操作。其中,r.F…...
【C语言】字符串
C语言用字符数组存放字符串,字符数组中的各元素依次存放字符串的各字符 一维字符数组:存放一个字符串(每个数组元素存放一个字符)二维字符数组:存放多个一维数组(字符串);二维数组的…...
云计算探索-DAS、NAS与SAN存储技术演进及其应用比较
1,介绍 随着信息技术的飞速发展,数据存储的需求日益增长,各种存储技术也应运而生。在众多的存储解决方案中,直接附加存储(Direct Attached Storage,简称DAS)、网络附加存储(Network …...
手机有线投屏到直播姬pc端教程
1 打开哔哩哔哩直播姬客户端并登录(按下图进行操作) 2 手机用usb数据线连接电脑(若跳出安装驱动的弹窗点击确定或允许),usb的连接方式为仅充电(手机差异要求为仅充电),不同品牌手机要求可能不一样,根据实际的来 3 在投屏过程中不要更改usb的连接方式(不然电脑会死机需要重启) …...
SOA、分布式、微服务之间的关系?
分布式它本身就是一种系统部署的架构理念,意思就是将一个系统拆分为各个部分,然后分别部署到不同的机器上去,SOA和微服务项目的部署方式都可以是分布式架构。 而SOA和微服务它们都是面向服务的架构,但是微服务相比于SOA在服务粒度…...
Java多线程学习(概念笔记)
面试题:并行和并发有什么区别? 现在都是多核CPU,在多核CPU下 并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU 并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程 面试题:创建线…...
【C++】set和map
set和map就是我们上篇博客说的key模型和keyvalue模型。它们属于是关联式容器,我们之前说过普通容器和容器适配器,这里的关联式容器就是元素之间是有关联的,通过上篇博客的讲解我们也对它们直接的关系有了一定的了解,那么下面我们先…...
yolov5 v7.0打包exe文件,使用C++调用
cd到yolo5文件夹下 pyinstaller -p 当前路径 -i logo图标 detect.py问题汇总 运行detect.exe找不到default.yaml 这个是yolov8里的文件 1 复制权重文件到exe所在目录。 2 根据报错提示的配置文件路径,把default.yaml复制放到相应的路径下。(缺少相应…...
保研线性代数机器学习基础复习2
1.什么是群(Group)? 对于一个集合 G 以及集合上的操作 ,如果G G-> G,那么称(G,)为一个群,并且满足如下性质: 封闭性:结合性:中性…...
网站如何设置二级域名/深圳外贸网络推广渠道
文章目录一、先说思路二、示例代码一、先说思路 1、使用cross-env修改系统常量,使程序知道接下来的操作要想那个服务器自动部署 2、使用ssh2操作服务器,将服务器上原有的项目改名,并放入记录文件夹 3、使用scp2将打包后的文件发送到对应的服…...
做政府网站哪家公司好/seo优化网站的注意事项
Redis SET 命令手册1. 可选项2. 返回值3. 历史变化4. 案例5. 模式从Redis 1.0.0 起可用 时间复杂度:O(1) 设置 key 以保存字符串 value。如果 key 已经保存了一个 value,则无论其类型如何,都会覆盖该值。成功的 SET 操作将丢弃与该键任何以前…...
wordpress模板dux/google推广公司哪家好
第三章 进程描述和控制 一、什么是进程: 开发操作系统是为了给应用程序提供一个方便、安全和一致的接口。 操作系统是计算机硬件和应用程序之间的一层软件,对应用程序和工具提供支持。 目标: 资源对多个应用程序是可用的; 物理处…...
旅游网站结构图/百度查重软件
近期学习 javafx 自己编写了一款软件 (网上尽管也有类似功能的软件,可是界面不够美观,功能比較单一,或者操作比較复杂) 软件官方网址:http://pcm.chujianyun.com 注:安装说明、使用说明、关于等…...
英文书 影印版 网站开发/站长工具seo查询软件
在idea使用htmlcss 简单仿制QQ会员官网主页页面 附带登录页面 跳转登陆页面 导航栏设置固定 底部信息栏附加根据鼠标在页面滑动的距离设置自动隐藏和显示 登录页面在点击登录后,实现覆盖整个页面,保持固定在页面中央位置,背景半透明化 …...
优秀网站赏析/怎么在百度免费推广
一个很影响用户体验的使用,就是文件传输失败,然后点了重发,还是失败。 一般用户遇到这个问题,任何APP被立刻卸载的几率也是有70%以上 因此迫在眉睫,但是好在我们公司这个项目没有推广太广(对于我是压力没那…...