当前位置:   article > 正文

vue-路由自动化

vue-路由自动化

Router

介绍

工程中的Router会根据src/views目录结构自动生成路由配置,路由结构与文件系统结构保持一致,不需要手动编写routes = [...],使得项目结构更加直观和易于理解。


配置

配置文件:

 router
    └─ index.ts
  • 1
  • 2
import {createRouter, createWebHistory, RouteRecordRaw} from "vue-router";


const ps = import.meta.glob("../views/**/page.ts", {eager: true, import: 'default'})
const cs = import.meta.glob("../views/**/index.vue")
const re: string[] = []
function createChildRoutes(basePath: string): RouteRecordRaw[] {
    const pObjs = Object.entries(ps)
    const routes: RouteRecordRaw[] = pObjs.filter(([path]) => {
        return path.startsWith(basePath) && path.split('/').length === basePath.split('/').length + 1;
    }).map(([path, params]) => {
        return createRoutes(path, params, (path) => {
            path = path.replace('../views', '').replace('/page.ts', '').replace('[', ':').replace(']', '')
            const name = path.replace(':', '').split('/').filter(Boolean).join('-') || 'index'
            const pathArr =  path.split('/')
            const routePath = pathArr[pathArr.length - 1]
            re.push(name)
            return [routePath, name]
        })
    })
    return routes;
}

function createRoutes(path: string, params: Record<string, any> | CustomRouterParams, getRoutePath: ((path: string) => string[])) {
    const compKey = path.replace('page.ts', 'index.vue')
    const [routePath, name] = getRoutePath(path)
    const data = params as Record<string, any> as CustomRouterParams
    const chs: RouteRecordRaw[] = [];

    if (routePath !== '/') {
        chs.push(...createChildRoutes(path.replace('page.ts', '')))
    }

    if (chs.filter((child) => child.path.startsWith('_')).length > 1) {
        throw new Error(`${path} 默认路由配置错误`)
    }

    const cd = chs.find((child) => child.path.startsWith('_'))

    if (cd) {
        const defaultRoute: RouteRecordRaw  = {...cd, path: ''}
        chs.push(defaultRoute)
        cd.path = cd.path.replace('_', '')
        if (cd.name) {
            cd.name = (cd.name as string).replace('_', '')
        }
    }

    const source = {
        ...data,
        ...(chs.length > 0 && { children: chs })
    };
    return {
        ...source,
        path: routePath,
        name: name,
        component: cs[compKey],
    } as RouteRecordRaw;
}

const routers: RouteRecordRaw[] = Object.entries(ps).map(([path, params]) => {
    return createRoutes(path, params, (path) => {
        const routePath =  path.replace('../views', '').replace('/page.ts', '').replace('[', ':').replace(']', '') || '/'
        const name = routePath.replace(':', '').split('/').filter(Boolean).join('-') || 'index'
        return [routePath, name]
    })
})

const finalRouters = routers.filter(r => !re.includes(r.name as string))
export const router = createRouter({history: createWebHistory(), routes: finalRouters})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

配置文件负责根据目录结构自动生成路由配置,目前支持的功能如下:

  • 生成基础配置项:path、name、component
  • 支持动态路由
  • 支持嵌套路由
  • 支持嵌套路由默认显示某个子路由
  • 支持重定向
  • 支持props传递给路由组件
  • 支持自定义路由元信息
  • 暂不支持命名视图和路由别名

只需关注目录结构,不需要关注此配置文件。


目录结构约定

views目录约定规范

基础约定

一个路由以index.vuepage.ts文件组成,二者缺一不可,index.vue为路由组件,page.ts为该路由的配置项。每个文件夹只存放一个路由。

views
  ├─ user
  |   └─ message
  |         ├─ index.vue
  |         └─ pages.ts
  ├─ index.vue
  └─ pages.ts
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

以上文件目录示例生成路由为:

const routers = [
    {
        path: '/',
        component: () => import('@/views/index.vue'),
        name: 'index',
        // 其他配置项从pages中取出
    },
    {
        path: '/user/message',
        component: () => import('@/views/message/index.vue'),
        name: 'user-message',
        // 其他配置项从pages中取出
    },
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 路由组件文件的路径即为path属性值,views为根目录'/',如上示例中目录结构views/user/message/index.vue,转path为:/user/message(如果被判定为嵌套路由则path: message,详见嵌套路由)
  • path属性值去掉'/'并以'-'相连形成路由名称,如上示例中目录结构views/user/message/index.vue,转name为:user-message,根路径默认name:'index'

动态路由

动态路由以[words]形式命名文件夹,如:文件夹名称[id]

views
  └─ user
      └─ [id]
           ├─ index.vue
           └─ pages.ts  
  • 1
  • 2
  • 3
  • 4
  • 5

以上文件目录示例生成路由为:

const routers = [
    {
        path: '/user/:id',
        component: () => import('@/views/user/[id]/index.vue'),
        name: 'user-id',
        // 其他配置项从pages中取出
    },
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 如上示例中目录结构views/user/[id]/index.vue,转path为:/user/:id(如果被判定为嵌套路由则path: ':id',详见嵌套路由)
  • 如上示例中目录结构views/user/[id]/index.vue,转name为:user-id

嵌套路由

嵌套路由判定规则:当前目录下存在路由组件文件时,下一级的所有路由组件文件都判定为子路由。('/'除外)

views
  └─ user
      ├─ [id]
      |    ├─ index.vue
      |    └─ pages.ts  
      ├─ index.vue
      └─ pages.ts   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

以上文件目录示例生成路由为:

const routers = [
    {
        path: '/user',
        component: () => import('@/views/user/index.vue'),
        name: 'user',
        // 其他配置项从pages中取出
        
        children: [
            {
                path: ':id',
                component: () => import('@/views/user/[id]/index.vue'),
                name: 'user-id',
                // 其他配置项从pages中取出
            }
        ]
    },
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 如上示例中目录结构,[id]文件夹下的路由作为子路由填充到父路由的children属性。
  • 如上示例中目录结构,子路由的path属性为:id,即父路由的相对路径。

嵌套路由默认子路由

在子路由文件夹名称以单个下划线'_'开头为默认子路由。

views
  └─ user
      ├─ _u1
      |   ├─ index.vue
      |   └─ pages.ts  
      ├─ u2
      |   ├─ index.vue
      |   └─ pages.ts  
      ├─ index.vue
      └─ pages.ts  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

以上文件目录示例生成路由为:

const routers = [
    {
        path: '/user',
        component: () => import('@/views/user/index.vue'),
        name: 'user',
        childern: [
            {
                path: '',
                component: () => import('@/views/user/_u1/index.vue'),
                name: 'user-_u1',
            },
            {
                path: 'u1',
                component: () => import('@/views/user/_u1/index.vue'),
                name: 'user-u1',
            },
            {
                path: 'u2',
                component: () => import('@/views/user/_u2/index.vue'),
                name: 'user-u2',
            },
        ]
        // 其他配置项从pages中取出
    },
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 默认子路由的name属性值会保留'_'下划线与区别其他路由,防止路由名称重复。
  • 最多只允许设置一个默认子路由,如果设置数量大于1,会抛出异常。异常信息:${path} 路由配置错误,'_'开头的默认子路由只能有一个

设置配置项

vue_template
   ├─ src
   ├─ ...
   └─ global.d.ts
  • 1
  • 2
  • 3
  • 4
  • global.d.ts文件是TypeScript项目中的一个全局类型声明文件。它用于声明全局变量、模块、接口或其他类型,使得这些声明在整个项目中都可以被访问,而无需显式导入。
  • global.d.ts文件中声明了可以对路由设置的配置项,如下:
interface CustomRouterParams {
    meta: {
        title: string
        menuOrder?: number
    }
    props?: boolean | Record<string, unknown> | ((route: any) => Record<string, unknown>)
    redirect?: string | Record<string, unknown> | ((to: any) => string | Record<string, unknown>)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • meta:路由元信息,可根据项目需求增加meta中的属性
  • props: 路由组件的props传递
  • redirect: 重定向

目录结构:

views
 ├─ user
 |  ├─ index.vue
 |  └─ pages.ts
 ├─ index.vue
 └─ pages.ts
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

views/pages.ts文件:

const pageConfig: CustomRouterParams = {
    meta: {
        title: 'home',
    },
    props: {name: 'tom', age: 20},// props: true | props: {name: 'tom', age: 20} | props: route => ({ id: route.params.id }) 
    redirect: '/user' // redirect: '/user' | redirect: {name: user} | redirect: to => {path: '/user', query: {q: to.query.search}} | ......
};
export default pageConfig;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

生成的路由如下:

const routers = [
    {
        path: '/',
        component: () => import('@/views/index.vue'),
        name: 'index',
        meta: {title: 'home'},
        props: {name: 'tom', age: 20}, // props: true | props: {name: 'tom', age: 20} | props: route => ({ id: route.params.id })
        redirect: '/user' // redirect: '/user' | redirect: {name: user} | redirect: to => {path: '/user', query: {q: to.query.search}} | ......
    },
    {
        path: '/user',
        //.......
        //.......
    },
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/817512
推荐阅读
相关标签
  

闽ICP备14008679号