动态路由——自动将指定目录下的文件注册为路由

项目配置信息如下

"vue": "^3.5.12",
"typescript": "~5.6.0",
"vite": "^5.4.10",

正文

在项目中,当路由组件变多时,手动去注册路由信息太过繁琐,在使用 Nuxt3 框架时发现该框架可以实现自动注册路由信息

于是找到源码参考了一下,发现可以通过 vite 的api import.mate.glob(string,object)拿到指定目录下所有的文件

那么,开始吧

在 src / router 目录下创建 auto-router.ts 文件,然后将目标拆解成一个个的需求并逐一解决

需求

  1. 匹配到指定目录的 .vue 文件

    // 基础
    import.meta.glob(globPattern, options)
    	- globPattern:必填项,string 或 string[]。!!!注意:只能接收静态字符串,所以这里必须写死
    	- options:配置对象
    		- eager:布尔值,默认false。为true时,直接同步导入模块;若为false。返回异步函数,也就是懒加载效果
    		- exclude:string[],排除匹配的文件。
            
    
    // 示例
    const files = import.meta.glob('../pages/**/*.vue')
    console.log(files, "@files")
    
    {
        ../pages/Demo.vue :  () => import("/src/pages/Demo.vue")
    }
    
  2. 将匹配到的文件转化成可用路径

    // 基础
    let routePath = path
            .replace('../pages', '')
            .replace(/\.vue$/, '')  // 匹配多级目录
            .replace(/\[([^\]]+)\]/g, ':$1')  // 匹配动态路由地址
            .replace(/_/g, ':')  // 允许传递参数,非必填
            .replace(/\/:/g, '/:')  // 修正路径格式
    
    // 示例
    pages/User/my.vue  ===> http://localhost:5174/user/my
    pages/User/about/name.vue  ===> http://localhost:5174/user/about/name
    pages/User/[id].vue  ===> http://localhost:5174/user/:123456 || http://localhost:5174/user/:id=999&title=888 
    pages/User/user_id.vue  ===> http://localhost:5174/user/user:123456 || http://localhost:5174/user/user:id=123456&title=888
    
  3. 将index自动转换成根目录

    // 示例:这里自动转换成小写,也就意味着可以创建 Index.vue
    
    if (routePath.toLowerCase() === '/index') {
        routePath = ''
    }
    
  4. 配置路由信息

    // 示例
    const route = {
        path: routePath === '' ? '/' : routePath,
        component: pages[path],
        name: routePath.replace(/\//g, '') || 'home',
        props: true  // 启用props接收路由参数
    }
    
    routes.push(route)  // 保存配置好的路由信息
    
    // 注意
    vue-router 可以并推荐处理懒加载组件,所以不需要额外配置为异步组件
    pages[path]: ===> () => import("/src/pages/About.vue")
    
  5. 收尾工作

    • 为了实现动态更新,需要把这些全放到一个方法中,该方法返回配置好的路由信息数组
    // 确保静态路由优先于动态路由
    routes.sort((a, b) => {
        const aDynamic = a.path.includes(':')
        const bDynamic = b.path.includes(':')
    
        if (aDynamic && !bDynamic) return 1
        if (!aDynamic && bDynamic) return -1
        return a.path.split('/').length - b.path.split('/').length
    })
    
    // 添加未匹配路径重定向(如果配置了redirectNotFoundTo,通过参数传递)
    if (redirectNotFoundTo) {
        routes.push({
            path: '/:pathMatch(.*)*',
            redirect: redirectNotFoundTo
        })
    }
    
    return routes
    

代码

添加了类型检查的版本,如果不需要可以关闭 ts 的严格模式或使用 js

scr / auto-router.ts

import type { Component } from "vue";
import type { RouteRecordRaw } from 'vue-router'

/**
 * 自动生成路由配置
 */
export const generateAutoRoutes = (redirectNotFoundTo: string = '/'): RouteRecordRaw[] => {
    const pages: Record<string, () => Promise<Component>> = import.meta.glob('../pages/**/*.vue', { eager: false })

    const routes: RouteRecordRaw[] = []

    for (const path in pages) {
        let routePath = path
            .replace('../pages', '')
            .replace(/\.vue$/, '')
            .replace(/\[([^\]]+)\]/g, ':$1')
            .replace(/_/g, ':')
            .replace(/\/:/g, '/:')

        if (routePath.toLowerCase() === '/index') {
            routePath = ''
        }

        const route: RouteRecordRaw = {
            path: routePath === '' ? '/' : `${routePath}`,
            component: pages[path],
            name: routePath.replace(/\//g, '') || 'home',
            props: true
        }

        routes.push(route)
    }

    routes.sort((a, b) => {
        const aDynamic = a.path.includes(':')
        const bDynamic = b.path.includes(':')

        if (aDynamic && !bDynamic) return 1
        if (!aDynamic && bDynamic) return -1
        return a.path.split('/').length - b.path.split('/').length
    })

    if (redirectNotFoundTo) {
        routes.push({
            path: '/:pathMatch(.*)*',
            redirect: redirectNotFoundTo
        })
    }

    return routes
}

src / index.ts

import { createRouter, createWebHistory } from "vue-router";
import { generateAutoRoutes } from "./auto-router"

const router = createRouter({
  history: createWebHistory(),
  routes: generateAutoRoutes()
});
export default router;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值