侧边栏壁纸
  • 累计撰写 53 篇文章
  • 累计创建 12 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

动态路由配置改写

Kirito
2024-04-07 / 0 评论 / 0 点赞 / 50 阅读 / 5760 字 / 正在检测是否收录...

文章中以Vue框架为例

常规路由

src/router/index.js

// src/router/index.js
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'index',
    component: () => import('../views/index.vue'),
    meta: {
      title: '首页'
    }
  },
  {
    path: '/about',
    name: 'about-index',
    component: () => import('../views/about/index.vue'),
    meta: {
      title: '关于'
    }
  },
  ...
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: routes
})

export default router

常规开发中,我们需要手动去设置修改 routes 的值来完成对路由变化的更新,这无疑增加了我们重复的开发工作以及维护牺牲,所以该篇文章提出了自动化改写方案避免此类没有必要的浪费。

思路

此处要提到团队开发中常用到的一个概念:约定大于配置,当我们可以通过团队约定的某些规范,来优化或规避各类手动配置项时,优先采用约定规范的方案实现。

一般情况下,我们开发项目的目录结构往往就可以体现出我们的路由结构,如下图:

Project
   |
   |--src--views
   |         |--index.vue
   |         |--About
   |             |--index.vue

那么我们实际可以利用文件目录来实现动态生成路由配置,为此我们给每一个路由对应的组件目录下增加一个 page.ts 文件,来辅助完成路径获取,并传递额外的值。

src/views/About/page.ts

export default {
  title: '关于'
}

工具

// Webpack环境下
require.context('../views', true, /\page.ts$/)

// Vite环境下
const pages = import.meta.glob('../views/**/page.ts', { eager: true, import: 'default' })

通过以上两个方法,可以扫描对应文件,并返回路径与文件内容组成的对象。

改写完成后(一级路由)

src/router/index.ts

import {
  createRouter,
  createWebHistory,
  type RouteMeta,
  type RouteRecordRaw,
  type RouteComponent
} from 'vue-router'

const pages: Record<string, RouteMeta | undefined> = import.meta.glob('../views/**/page.ts', {
  eager: true,
  import: 'default'
})
const comps: Record<string, RouteComponent> = import.meta.glob('../views/**/index.vue')
const routes: Array<RouteRecordRaw> = Object.entries(pages).map(([path, page]) => {
  const originPath = path
  const compPath = originPath.replace('page.ts', 'index.vue')
  path = path.replace('../views', '').replace('/page.ts', '').toLowerCase() || '/'
  const name =
    path
      .split('/')
      .filter((p) => p)
      .join('-') || 'index'
  return {
    path,
    name,
    component: comps[compPath],
    meta: page
  }
})

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: routes
})

export default router

以上改写只支持了一级路由的情况,若有多级路由的需求,还需另外改写

多级路由改写

src/interfaces/common.ts

// 路由组件配置文件格式
export interface iPage {
  path?: string         // 用于辅助动态生成时类型检查,各page.ts中不填写
  parent?: string       // 父组件path
  name: string          // 路由name
  level: number         // 路由等级
  title?: string        // 所需传参,此处以title为例
}

src/router/index.ts

import type { iPage } from '@/interface/common'
import {
  createRouter,
  createWebHistory,
  type RouteMeta,
  type RouteRecordRaw,
  type RouteComponent
} from 'vue-router'

interface iRouteMeta extends RouteMeta {
  name: string
  level: number
}

const pages: Record<string, iRouteMeta> = import.meta.glob('../views/**/page.ts', {
  eager: true,
  import: 'default'
})
const comps: Record<string, RouteComponent> = import.meta.glob('../views/**/index.vue')

// 格式化pages对象为数组
const arrPages: iPage[] = Object.entries(pages).map(([path, page]) => ({
  path,
  ...page
}))

// 动态初始化路由配置 Routes
const generateRoutes = (arr: iPage[], level: number, parent?: string): Array<RouteRecordRaw> => {
  const routes = arr.filter((item) => item.level === level && (!parent || item.parent === parent))
  return routes.map((item) => {
    const path = item.path?.replace('../views', '').replace('/page.ts', '').toLowerCase() || '/'
    const name = item.name
    const component = item.path ? comps[item.path.replace('page.ts', 'index.vue')] : null
    const meta = {
      title: item.title
    }
    const children = generateRoutes(arr, level + 1, item.parent)
    return {
      path,
      name,
      component,
      meta,
      children
    }
  })
}

const routes: Array<RouteRecordRaw> = generateRoutes(arrPages, 1)

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: routes
})

export default router

Github示例项目地址

0

评论区