当前位置: 首页 > news >正文

react/vue vite ts项目中,自动引入路由文件、 import.meta.glob动态引入路由 无需手动引入

utils/autoRouteHelper.ts

// src/utils/autoRouteHelper.ts
import { lazy } from "react";
import withLoading from "@/components/router/withLoading";/** 自动生成某个文件夹下的子路由 */
interface RouteItem {path: string;element?: any;children?: RouteItem[];handle?: {title: string;};
}/*** 生成嵌套路由树(保留 children 树结构,排除 components)* @param globModules 模块对象* @param baseDir 模块路径* @param titleMap 路由标题映射表* @returns 返回树形结构路由数据*/
export function generateNestedRoutes(globModules: Record<string, () => Promise<any>>,baseDir: string,titleMap: Record<string, string> = {}
): RouteItem[] {const root: Record<string, any> = {};for (const [fullPath, loader] of Object.entries(globModules)) {if (fullPath.includes("/components/")) continue;const reg = new RegExp(`${baseDir}/(.*)/index\\.tsx$`, "i");const match = fullPath.match(reg);if (!match) continue;const subPath = match[1].replace(/\\/g, "/"); // windows 兼容const segments = subPath.split("/"); // ["pageb", "list"]let current = root;// let fullSegmentPath = "";for (let i = 0; i < segments.length; i++) {const segment = segments[i];// fullSegmentPath += (i === 0 ? "" : "/") + segment;if (!current[segment]) {current[segment] = {path: segment,childrenMap: {}};}// 最后一层,挂 element 和 titleif (i === segments.length - 1) {current[segment].element = withLoading(lazy(loader));current[segment].handle = {title: titleMap[subPath.toLowerCase()] || segment};}current = current[segment].childrenMap;}}// 将 childrenMap 转为 children[]function convertToTree(obj: Record<string, any>): RouteItem[] {return Object.values(obj).map(({ childrenMap, ...rest }) => {const node: RouteItem = { ...rest };const children = convertToTree(childrenMap);if (children.length > 0) node.children = children;return node;});}return convertToTree(root);
}/** 合并所有模块的默认导出,适合用于路由模块化(eager 模式) */
export function mergeModuleRoutes(modules: Record<string, any>
): any[] {const routes: any[] = [];Object.values(modules).forEach((mod: any) => {if (Array.isArray(mod.default)) {routes.push(...mod.default);} else if (mod.default) {routes.push(mod.default);}});return routes;
}

react路由使用

目录\router\modules\supplier.ts

import.meta.glob(‘@/pages/supplier/**/index.tsx’); 自动获取pages/supplier目录下的所有页面传递给generateNestedRoutes返回路由不限制层级,可以一二级也可以一二三四级别等等

\router\modules
新增路由文件 如supplier.ts
import { lazy } from "react";
import withLoading from "@/components/router/withLoading";
import { generateNestedRoutes } from "@/utils/routerHelper";const personalPageModules = import.meta.glob('@/pages/supplier/**/index.tsx');const titleMap: Record<string, string> = {list: "供应商列表",// 你可以继续添加其他路径对应的标题
};/** 供应商管理 */
const supplier: Array<any> = [{path: "supplier",element: withLoading(lazy(() => import("@/pages/supplier/index"))),handle: {title: "供应商管理",},children:[...generateNestedRoutes(personalPageModules,"supplier",titleMap)]},
];
console.log(supplier,"供应商管理")
export default supplier;router/index.ts目录中
const modules = import.meta.glob('./modules/*.ts', { eager: true });...mergeModuleRoutes(modules),
自动获取modules目录下的所有路由文件

vue路由中使用

routerHelper.ts

// src/utils/autoRouteHelper.ts
// src/utils/autoRouteHelper.ts
/*** 自动生成某个模块文件夹下的子路由(用于 Vue Router)*/interface TitleMap {[key: string]: string;
}interface AutoRouteOptions {/** 模块目录,如 'views/merchantmanage' */baseDir: string;/** 路由标题映射表 */titleMap?: TitleMap;/** 排除目录数组,如 ['components', 'common'] */excludeDirs?: string[];
}/*** 自动生成某个目录下的子路由,支持多级目录,支持排除子目录* @param globModules import.meta.glob 的结果* @param options 配置项*/
export function generateChildrenRoutes(globModules: Record<string, () => Promise<any>>,options: AutoRouteOptions
) {const { baseDir, titleMap = {}, excludeDirs = [] } = options;return Object.entries(globModules).map(([fullPath, loader]) => {// 1. 判断是否命中排除目录const shouldExclude = excludeDirs.some((dir) =>fullPath.includes(`${baseDir}/${dir}/`));if (shouldExclude) return null;// 2. 提取 baseDir 后的子路径部分const match = fullPath.match(new RegExp(`${baseDir}/(.+)\\.vue$`));if (!match) return null;const subPath = match[1]; // 例:user/detail/index 或 homeconst segments = subPath.split('/');// 构建路由 path,忽略 indexlet routePath = segments.map((seg) => (seg === 'index' ? '' : seg)).filter(Boolean).join('/');if (!routePath) routePath = '';const routeName = routePath.replace(/\//g, '-');return {path: routePath,name: routeName,component: loader,meta: {title: titleMap[routePath.toLowerCase()] || segments.at(-1) || routePath}};}).filter(Boolean) as any[];
}/** 合并所有模块的默认导出,适合用于路由模块化(eager 模式) */
export function mergeModuleRoutes(modules: Record<string, any>
): any[] {const routes: any[] = [];Object.values(modules).forEach((mod: any) => {if (Array.isArray(mod.default)) {routes.push(...mod.default);} else if (mod.default) {routes.push(mod.default);}});return routes;
}

/使用实例

const modules = import.meta.glob('@/views/merchantmanage/**/*.vue');const routes = generateChildrenRoutes(modules, {baseDir: 'views/merchantmanage',excludeDirs: ['components', 'fragments', 'common'],titleMap: {user: '用户管理','user/detail': '用户详情'}
});

这样就会排出默认components或者自定义的目录作为路由

无需要在手动写进去再去引入

http://www.xdnf.cn/news/1141399.html

相关文章:

  • 7月18日总结
  • Java全栈工程师面试实录:从Spring Boot到AI大模型的深度技术解析
  • 基于K8s ingress灰度发布配置
  • 【Docker#2】容器历史发展 | 虚拟化实现方式
  • Java大厂面试实录:从Spring Boot到AI微服务架构的深度解析
  • [源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精
  • 如何快速下载 MT4 交易平台
  • div和span区别
  • 智象科技赋能金融、证券行业 IT 运维
  • Git使用与管理
  • mac mlx大模型框架的安装和使用
  • BIST会对锁步核做什么?
  • 【PTA数据结构 | C语言版】根据后序和中序遍历输出前序遍历
  • Kubernetes (k8s)、Rancher 和 Podman 的异同点分析
  • Copula 回归与结构方程模型:R 语言构建多变量因果关系网络
  • 异世界历险之数据结构世界(排序(插入,希尔,堆排))
  • mysql 性能优化入门
  • 搜索引擎优化全攻略:提升百度排名优化
  • JAVA 使用Apache POI合并Word文档并保留批注的实现
  • 前端下载文件并按GBK编码解析内容
  • ADVB协议内容分析
  • MyBatis 动态 SQL:让 SQL 语句随条件灵活变化
  • 【科研绘图系列】R语言绘制分组箱线图
  • 【锂电池剩余寿命预测】TCN时间卷积神经网络锂电池剩余寿命预测(Pytorch完整源码和数据)
  • 基于vue框架的房屋租赁系统设计与实现zrd8i(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 信息论至AI实践:交叉熵的原理全景与应用深度解析
  • 【后端】.NET Core API框架搭建(10) --配置163邮件发送服务
  • 数据统计模块后端架构解析:从Controller到SQL的ECharts数据对接实践
  • 实现库存显示和状态按钮的Question
  • 如何将 iPhone 备份到笔记本电脑?