Skip to content

动态生成路由

vue3+vite3根据目录动态生成路由

页面层级

text
├── App.vue
├── main.ts
├── router
│   ├── index.ts
│   └── pTest.ts
├── store
│   └──test.store.ts
├── utils
│   ├── index.ts
│   ├── ...
│   └── interceptor.ts
└── views
    ├── pTest
    │   ├── components
    │   ├── test
    │   │   └── testA.vue
    │   ├── testA.vue
    │   └── testB.vue
    └── pageQuickIn.vue

routerGenerate

  • 约定如下:
  • 例:页面如下 views/pTest/testA
    • 1: path => pTest/testA
    • 2: name => PTestTestA
    • 3: meta => pagesOptions中配置
ts
import { RouteRecordRaw } from 'vue-router';

/**
 * 动态生成路由
 * @param viteModules https://cn.vitejs.dev/guide/features#glob-import
 */
export function routerGenerate(viteModules: Record<string, () => Promise<any>>, pagesOptions: any = {}): Array<RouteRecordRaw> {
  // 过滤掉components下的vue文件
  const _viteModules = Object.keys(viteModules)
    .filter((key) => !key.includes('components'))
    .reduce((acc, key) => {
      acc[key] = viteModules[key];
      return acc;
    }, {} as typeof viteModules);

  const routes: Array<RouteRecordRaw> = Object.entries(_viteModules).map(([modulePath, component]) => {
    // path 页面路由 目录路径 如:/pTest/testA
    const path = modulePath.replace('../views', '').replace('.vue', '') || '/';
    // 目录层级拆分 ['',pTest,testA],['',pTest,test,testA],
    const pathArr = path.split('/');
    const pathArrLen = pathArr.length;
    // 模块文件目录层级-数组形式 [pTest,testA],[pTest,test,testA]
    const nameArr = pathArr.slice(1, pathArrLen);
    // console.log(nameArr);
    const name = nameArr
      .map((_e) => {
        return _e.replace(/^[a-z]/, (match) => match.toUpperCase());
      })
      .join(''); // 页面name 路径拼接-驼峰 PTestTestA PTestTestTestA
    // 当前页面配置 routeNameArr.join('/')页面所在分包path 用于匹配页面配置
    const currentPageOptions = pagesOptions[pathArr.slice(2, pathArrLen).join('/')];
    // console.log(currentPageOptions);
    return {
      path: path + (currentPageOptions?.routeParam || ''),
      meta: currentPageOptions?.meta || {},
      name,
      component,
    };
  });
  // console.log(routes);
  return routes;
}

pTest.router

ts
import { RouteRecordRaw } from 'vue-router';
import { routerGenerate } from '@/common/utils';

// pagesOptions
const pTestPagesOptions = {
  // testA: {
  //   meta: {
  //     title: '测试页面A',
  //     KeepAlive: true,
  //   },
  // },
  // 'test/testA': {
  //   meta: {
  //     title: '测试页面A',
  //     KeepAlive: true,
  //   },
  //   routeParam: '/:id',
  // },
};
const routes: Array<RouteRecordRaw> = routerGenerate(import.meta.glob('../views/pTest/**/*.vue'), pTestPagesOptions);
export default routes;

createRouter

ts
import { createRouter, RouteRecordRaw, createWebHashHistory } from 'vue-router';
import pTest from './pTest';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'pageQuickIn',
    meta: {
      title: '',
      keepAlive: false,
    },
    component: () => import('../views/pageQuickIn.vue'),
    // redirect: '/pTest/testA',
    children: [],
  },
  ...pTest,
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

export default router;
既来之,则安之。