在开发vue项目时候,需要手动创建路由指向到目录,如果是小项目,路由不多的情况手动配置没有问题,如果遇到中大项目呢,增加一个路由,未免会显得格外枯燥,后期路由的维护成本也会很高,那么可以自动生成路由就很有必要了。
搭建vue项目
vite+vue3+ts创建一个vue3项目
约定
为了避免将一个不必要的文件夹配置为路由,我们约定目录下拥有page.ts
文件为路由,且入口文件均为index.vue
page.ts
文件会暴露出一个对象,这个对象会添加设置为路由的meta属性
根据上边的约定一个路由最少会有如图文件

1 2 3 4 5 6
| import {RouteMeta} from "vue-router"; const meta:RouteMeta = { name:"test", } export default meta;
|
1 2 3 4 5 6 7 8 9 10 11
| <template> <div class="test">test</div> </template>
<script setup lang="ts">
</script>
<style scoped> </style>
|
是不是觉得创建这两个文件也很麻烦,没关系后边会说怎么用命令去创建这两个文件
代码
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
| import {createRouter, createWebHashHistory, RouteMeta, RouteRecordRaw} from "vue-router";
const selfRouter:RouteRecordRaw[] = [ { path: '/:pathMatch(.*)', component: () => import((`../views/404/index.vue`)), }, { path: '/', redirect:'/home' } ]
const compModels:Record<string, any> = import.meta.glob('../views/**/index.vue');
const pageModels:Record<string, any> = import.meta.glob('../views/**/page.ts', { eager: true, import:'default' });
const pageArr:string[][] = Object.keys(pageModels).map(val => val.split('/').slice(2, -1)); let routes:RouteRecordRaw[] = [];
function createNode(arr: string[][], fatherPath: string, children: RouteRecordRaw[],length:number) { for (let item of arr) { if (item.length === length) { const node:RouteRecordRaw = { path: `${fatherPath}/${item[length - 1]}`, children: [], } if (node.path === '/' + item.join('/')) { const path = '../views' + node.path; node.meta = pageModels[path + '/page.ts'] as RouteMeta; if(node.meta.redirect){ node.redirect = node.meta.redirect as string; } node.name = node.meta.name as string; node.component = compModels[path + '/index.vue'] createNode(arr, node.path, node.children, length + 1); children.push(node); node.path = node.path.toLowerCase(); } } } }
createNode(pageArr,'',routes,1); routes.push(...selfRouter) const router = createRouter({ history: createWebHashHistory(), routes }) export default router;
|
效果
根据如上代码,会根据目录结构生成路由文件

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
| [ { "path":"/home", "children":[ { "path":"/home/user", "children":[
], "meta":{ "name":"user" }, "name":"user", "component": () => import((`../views/Home/User/index.vue`)), } ], "meta":{ "name":"home" }, "name":"home", "component": () => import((`../views/Home/index.vue`)), }, { "path":"/test", "children":[
], "meta":{ "name":"test" }, "name":"test", "component": () => import((`../views/Test/index.vue`)), }, { "path":"/:pathMatch(.*)", "component": () => import((`../views/404/index.vue`)), }, { "path":"/", "redirect":"/home" } ]
|
命令生成文件、文件夹
在项目根目录创建/createFile/index.js
编写如下代码
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
| import fs from 'fs'; import * as readline from "readline"; import {pageTemplate,indexTemplate} from "./template.js"; const read = readline.createInterface({ input: process.stdin, output: process.stdout }); const createFile = (dirTitle, path) => { fs.writeFileSync(`./src/views${path}/${dirTitle}/page.ts`, pageTemplate(dirTitle)); fs.writeFileSync(`./src/views${path}/${dirTitle}/index.vue`, indexTemplate(dirTitle)); console.log('组件创建成功,文件路径为:',path + '/' + dirTitle.slice(0,1).toUpperCase() +dirTitle.slice(1).toLowerCase()); console.log(`\x1B[36m此组件路由为:${(path + '/' + dirTitle).toLowerCase()}\x1B[0m`); read.close(); } const createDir = (title, path) => { title = title.slice(0, 1).toUpperCase() + title.slice(1).toLowerCase() fs.mkdir(`./src/views${path}/${title}`, () => { createFile(title, path) }); } inputName(); function inputName(){ read.question('请输入组件名称:',(title)=>{ if (!/^[a-zA-Z]+$/.test(title)) { console.log('\x1B[31m组件名称必须为英文\x1B[0m'); inputName(); }else { inputPath(title); } }); } function inputPath(title){ read.question('请输入组件所处路径:(例如:/Home,意思为在Home下创建此组件)', (path) => { if(!/^[a-zA-Z\/]+$/.test(path) && path[0] !== '/'){ console.log('\x1B[31m路径开头必须为“/“且必须全为英文\x1B[0m'); inputPath(title); } else { title = title.slice(0,1).toUpperCase() +title.slice(1).toLowerCase(); createDir(title, path) } }); }
|
在项目根目录创建/createFile/template.js
编写如下代码
如下代码根据自己需要自由更改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| export const pageTemplate = (name) => {return `import {RouteMeta} from "vue-router"; const meta:RouteMeta = { name:"${name}", } export default meta;` }
export const indexTemplate = (name) => { return `<template> <div class="${name}">${name}</div> </template>
<script setup lang="ts">
</script>
<style scoped> </style>` }
|
结语
没有编写动态路由等方面的代码、因为我的项目中使用的功能如上代码已经完全可以满足。文中若有错误,欢迎指正!