Vite+vue3的约定式路由实践

  • Vite+vue3的约定式路由实践;
  • 实现了类似umi的约定式路由,并实现了全局layouts的和404的路由;
  • 本文大量借鉴了下面链接的文章,侵权删

路由规则

生成的方式,我们尽量与 umi.js 保持一致, 并实现(umijs)的约定式 layouts404路由。但避免一个问题:避免将不需要的组件映射成路由

  • pages/index.tsx/
  • pages/blog/index.tsx/blog
  • pages/about.tsx/about

umi中,我们可以在config.ts中这样配置来避免将不需要的组件映射成路由

javascript 复制代码
conventionRoutes: {
    // 规定只有index文件会被识别成路由
    exclude: [
      /(?<!(index|\[index\]|404)(\.(js|jsx|ts|tsx)))$/,
      /model\.(j|t)sx?$/,
      /\.test\.(j|t)sx?$/,
      /service\.(j|t)sx?$/,
      /models\//,
      /components\//,
      /services\//,
    ],
  },

在这里,我们暂时使用这个正则,也可以根据项目中是否使用了jsx来增加.vue文件后缀

ini 复制代码
const modules = import.meta.glob("/src/pages/**/{index,404}.{ts,tsx}");

工程目录示例

复制代码
├─layouts
│  │  index.tsx
├─pages
│  │
│  └─demo
│      │  index.tsx
│      │
│      └─demo-child
│              hello-world.tsx
│              index.tsx

话不多说,直接上代码

route/plugin.ts 复制代码
import { set } from "lodash-es";

import type { RouteRecordRaw } from "vue-router";
/**
 * 根据 pages 目录生成路径配置
 */
function generatePathConfig(): Record<string, any> {
  // 扫描 src/pages 下的所有具有路由文件
  const modules = import.meta.glob("/src/pages/**/{index,404}.{ts,tsx}");

  const pathConfig = {};
  Object.keys(modules).forEach((filePath) => {
    const routePath = filePath
      // 去除 src/pages 不相关的字符
      .replace("/src/pages/", "")
      // 去除文件名后缀
      .replace(/.tsx?/, "")
      // 转换动态路由 $[foo].tsx => :foo
      .replace(/\$\[([\w-]+)]/, ":$1")
      // 转换以 $ 开头的文件
      .replace(/\$([\w-]+)/, "$1")
      // 以目录分隔
      .split("/");
    // 使用 lodash.set 合并为一个对象
    set(pathConfig, routePath, modules[filePath]);
  });
  return pathConfig;
}

/**
 * 将文件路径配置映射为 vue-router 路由
 */
function mapPathConfigToRoute(cfg: Record<string, any>): RouteRecordRaw[] {
  // route 的子节点为数组
  return Object.entries(cfg).map(([routePath, child]): RouteRecordRaw => {
    let currentRoute: RouteRecordRaw = {
      path: routePath,
      name: routePath,
    };
    // () => import() 语法判断 转换为组件
    if (typeof child.index === "function" || typeof child === "function") {
      currentRoute.component = child.index || child;
    }
    const { index, ...rest } = child;
    // 还有子级为目录,查找下一层级
    if (Object.keys(rest).length > 0) {
      currentRoute.children = mapPathConfigToRoute(rest);
    }
    return currentRoute;
  });
}

// 提取公共layouts
const getLayouts = (): (() => Promise<any>) => {
  const layouts = import.meta.glob("/src/layouts/index.{ts,tsx}");
  if (!layouts) return () => Promise.resolve(undefined);
  return Object.entries(layouts)[0][1];
};

function generateRouteConfig(): RouteRecordRaw[] {
  const { ...pathConfig } = generatePathConfig();
  return [
    {
      path: "",
      name: "",
      component: getLayouts(),
      children: mapPathConfigToRoute(pathConfig),
    },
    { path: "/:pathMatch(.*)*", redirect: "/404" },
  ];
}

const routeConfig = generateRouteConfig();
export { routeConfig };

在router中使用

typescript 复制代码
import { createRouter, createWebHistory } from "vue-router";
import { routeConfig } from "./plugin";

const router = createRouter({
  history: createWebHistory(""),
  routes: routeConfig,
});

router.beforeEach(async (to: any) => {
  
});

router.afterEach(() => {
  
});

export default router;

结语

暂无

相关推荐
毕业设计70320 小时前
(免费领源码) 基于微信小程序的预制菜商城的设计与实现25172-java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
vue.js·python·mysql·微信小程序·pycharm·微信开发者工具·推荐算法
xifangge202520 小时前
AGENTS.md 怎么写?涵盖 Java、Python、Vue、Go 的 8 套开箱即用模板
java·vue.js·python
雪芽蓝域zzs21 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
Bs_MoneyMagnet1 天前
基于springboot+vue的旅游景区点评系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·旅游
ID34610744201 天前
【课程设计】基于Spring Boot+Vue的校园共享无人机服务系统设计与实现-计算机毕设 附源码44219
javascript·vue.js·spring boot·python·node.js·php·课程设计
BillKu1 天前
Vue3 可拖拽分栏布局:两种实现方式详解
javascript·vue.js·ecmascript
雪芽蓝域zzs1 天前
第三十七节:防抖、节流封装(composables 通用函数,搜索框防重复请求)
前端·javascript·vue.js
Bs_MoneyMagnet1 天前
基于springboot+vue的爱心众筹系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·管理系统
Bs_MoneyMagnet1 天前
基于springboot+vue的在线音乐管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
岁岁种桃花儿1 天前
Vue组件化编程第二篇:非单位件组件
前端·javascript·vue.js