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等工具都提供了文件扫描的接口,只是不能使用变量进行路径扫描,必须字面量(常量),好在支持通配符。解决起来不难。对于后端很早例如spring框架就具备了自动扫描功能,对于前端,有对应方案但是应用的不是很多,用好了很舒服。

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

其他部分可以不用动,不到100行代码,你便妥妥的拥有了高大上的自动路由功能。

副作用

这样处理虽然开发方便,但是也有它的局限和副作用。副作用就是分包问题,由于所有的模块获取菜单定义必须读文件,因此无法懒加载,会导致扫描过程需要加载全部的模块,这样一来当模块非常多的时候加载会比较耗资源,也无法细化的分包。但对于中小项目一个gzip包全部load下来还是问题不大。大型项目可能要采用其它方案例如自动化脚本来输出路由。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git命令上传本地项目至github

记录如何创建个人仓库并上传已有代码至github in MacOS环境 0. 首先下载git 方法很多 这里就不介绍了 1. Github Create a new repository 先在github上创建一个空仓库&#xff0c;用于一会儿链接项目文件&#xff0c;按照自己的需求设置name和是否private 2.push an exis…

【LeetCode】LeetCode 547. 省份数量(Java版 什么是并查集)

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 一、题目描述 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间接相连。 省份 是一组直…

Python爬虫-懂车帝城市销量榜单

前言 本文是该专栏的第23篇,后面会持续分享python爬虫干货知识,记得关注。 最近粉丝留言咨询某汽车平台的汽车销量榜单数据,本文笔者以懂车帝平台为例,采集对应的城市汽车销量榜单数据。 具体的详细思路以及代码实现逻辑,跟着笔者直接往下看正文详细内容。(附带完整代码…

【NLP笔记】大模型prompt推理(提问)技巧

文章目录 prompt概述推理&#xff08;提问&#xff09;技巧基础prompt构造技巧进阶优化技巧prompt自动优化 参考链接&#xff1a; Pre-train, Prompt, and Predict: A Systematic Survey of Prompting Methods in Natural Language Processing预训练、提示和预测&#xff1a;NL…

如何使用Windows电脑部署Lychee私有图床网站并实现无公网IP远程管理本地图片

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-MSVdVLkQMnY9Y2HW {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

HarmonyOS ArkTS 骨架屏加载显示(二十五)

目录 前言1、骨架屏代码显示2、代码中引用3、效果图展示 前言 所谓骨架屏&#xff0c;就是在页面进行耗时加载时&#xff0c;先展示的等待 UI, 以告知用户程序目前正在运行&#xff0c;稍等即可。 等待的UI大部分是 loading 转圈的弹窗&#xff0c;有的是自己风格的小动画。其实…

《QDebug 2024年3月》

一、Qt Widgets 问题交流 1. 二、Qt Quick 问题交流 1.Qt5 ApplicationWindow 不能使用父组件 Window 的 transientParent 属性 ApplicationWindow 使用 transientParent 报错&#xff1a; "ApplicationWindow.transientParent" is not available due to compone…

亚马逊自养号测评:风险剖析与防范策略全解析

亚马逊平台竞争激烈&#xff0c;美站乃至全球市场的卖家为提升产品排名和销量&#xff0c;纷纷用起了自养号测评。然而&#xff0c;自养号测评技术因其较高的技术门槛&#xff0c;使得许多卖家因缺乏对其原理和底层环境搭建的了解&#xff0c;而面临账号关联和封禁的风险。本文…

SpringBoot常见注解有哪些

Spring Boot的核心注解是SpringBootApplication , 他由几个注解组成 : ● SpringBootConfiguration&#xff1a; 组合了- Configuration注解&#xff0c;实现配置文件的功能&#xff1b; ● EnableAutoConfiguration&#xff1a;打开自动配置的功能&#xff0c;也可以关闭某个自…

实景三维技术:开启自然资源管理的新篇章

随着科技的不断进步&#xff0c;实景三维技术已经在多个领域得到了广泛的应用。而在自然资源管理领域&#xff0c;实景三维技术更是发挥着越来越重要的作用。本文将介绍实景三维在自然资源管理领域的应用&#xff0c;探讨其带来的优势和变革。一、什么是实景三维技术&#xff1…

Python多任务处理---多线程

引入 生活中&#xff0c;我们在电脑上打开了一个word, 这个word对操作系统来说就是一个进程。我们在进行word操作的时候&#xff0c;比如在你打字的时候&#xff0c;该word同时可以进行文字检查。发现了没&#xff0c;在同一个进程中&#xff0c;我们也可以进行同时操作。…

Rust 02.控制、引用、切片Slice、智能指针

1.控制流 //rust通过所有权机制来管理内存&#xff0c;编译器在编译就会根据所有权规则对内存的使用进行 //堆和栈 //编译的时候数据的类型大小是固定的&#xff0c;就是分配在栈上的 //编译的时候数据类型大小不固定&#xff0c;就是分配堆上的 fn main() {let x: i32 1;{le…

分类任务中的评估指标:Accuracy、Precision、Recall、F1

概念理解 T P TP TP、 T N TN TN、 F P FP FP、 F N FN FN精度/正确率&#xff08; A c c u r a c y Accuracy Accuracy&#xff09; 二分类查准率 P r e c i s i o n Precision Precision&#xff0c;查全率 R e c a l l Recall Recall 和 F 1 − s c o r e F1-score F1−s…

linux 一些命令

文章目录 linux 一些命令fdisk 磁盘分区parted 分区文件系统mkfs 格式化文件系统fsck 修复文件系统 mount 挂载swap 交换分区清除linux缓存df du 命令raid 命令基本原理硬raid 和 软raid案例raid 10 故障修复&#xff0c;重启与卸载 lvm逻辑卷技术LVM的使用方式LVM 常见名词解析…

书生·浦语大模型-第一节课笔记

视频总结 23年发布的模型在一些材料中归位指令微调模型&#xff0c;后面逐渐升级应该已经是train的模型了 技术报告总结 InternLM2 Technical Report 评测与特点 6 dimensions and 30 benchmarks, long-context modeling, and open-ended subjective evaluations长文本…

与鲸同行,智领未来!和鲸科技“人工智能+X”学科建设合作交流会(北京站)圆满结束!

在国家加快发展新质生产力的大背景下&#xff0c;3月25日下午&#xff0c;和鲸科技 2024 年“人工智能X”学科建设合作交流会&#xff08;北京站&#xff09;暨“AIX”实验室建设与供应商选型座谈会顺利召开。为提供更为集中和专业的讨论环境&#xff0c;本次会议特别采取闭门审…

环境温度对测量平板有什么影响

环境温度可以对测量平板有影响。温度变化可以导致平板的尺寸发生变化。根据热膨胀原理&#xff0c;当环境温度升高时&#xff0c;平板的尺寸会扩大&#xff1b;当环境温度降低时&#xff0c;平板的尺寸会缩小。这种尺寸变化可能会导致测量结果的误差。因此&#xff0c;在测量平…

【蓝桥杯第十三届省赛B】(部分详解)

九进制转十进制 #include <iostream> #include<math.h> using namespace std; int main() {cout << 2*pow(9,3)0*pow(9,2)2*pow(9,1)2*pow(9,0) << endl;return 0; }顺子日期 #include <iostream> using namespace std; int main() {// 请在此…

一文了解JAVA的常用API

目录 常用kpimathSystemRuntimeObjectObjectsBigIntegerBigDecima正则表达式包装类 常用kpi 学习目的&#xff1a; 了解类名和类的作用养成查阅api文档的习惯 math 工具类。因为是工具类&#xff0c;因此直接通过类名.方法名(形参)即可直接调用 abs&#xff1a;获取参数绝对…

flume配置文件后不能跟注释!!

先总结&#xff1a;Flume配置文件后面&#xff0c;不能跟注释&#xff0c;可以单起一行写注释 报错代码&#xff1a; [ERROR - org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:158)] Unable to deliver event. Exception follows. org.apache.flume.EventDel…