├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── dist ├── index.d.ts └── index.js ├── lib └── index.ts ├── package.json ├── test └── test.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,windows,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=node,windows,visualstudiocode 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional REPL history 62 | .node_repl_history 63 | 64 | # Output of 'npm pack' 65 | *.tgz 66 | 67 | # Yarn Integrity file 68 | .yarn-integrity 69 | 70 | # dotenv environment variables file 71 | .env 72 | .env.test 73 | 74 | # parcel-bundler cache (https://parceljs.org/) 75 | .cache 76 | 77 | # next.js build output 78 | .next 79 | 80 | # nuxt.js build output 81 | .nuxt 82 | 83 | # vuepress build output 84 | .vuepress/dist 85 | 86 | # Serverless directories 87 | .serverless/ 88 | 89 | # FuseBox cache 90 | .fusebox/ 91 | 92 | # DynamoDB Local files 93 | .dynamodb/ 94 | 95 | ### VisualStudioCode ### 96 | .vscode/* 97 | !.vscode/settings.json 98 | !.vscode/tasks.json 99 | !.vscode/launch.json 100 | !.vscode/extensions.json 101 | 102 | ### VisualStudioCode Patch ### 103 | # Ignore all local history of files 104 | .history 105 | 106 | ### Windows ### 107 | # Windows thumbnail cache files 108 | Thumbs.db 109 | Thumbs.db:encryptable 110 | ehthumbs.db 111 | ehthumbs_vista.db 112 | 113 | # Dump file 114 | *.stackdump 115 | 116 | # Folder config file 117 | [Dd]esktop.ini 118 | 119 | # Recycle Bin used on file shares 120 | $RECYCLE.BIN/ 121 | 122 | # Windows Installer files 123 | *.cab 124 | *.msi 125 | *.msix 126 | *.msm 127 | *.msp 128 | 129 | # Windows shortcuts 130 | *.lnk 131 | 132 | # End of https://www.gitignore.io/api/node,windows,visualstudiocode 133 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | coverage/ 3 | .history 4 | tsconfig.json 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | install: 5 | - npm install 6 | script: 7 | - npm run cover 8 | # Send coverage data to Coveralls 9 | after_script: 'cat coverage/lcov.info | node_modules/coveralls/bin/coveralls.js' 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [vue-router-auto](https://github.com/MrHzq/vue-router-auto) 2 | 3 | [![Build Status](https://travis-ci.org/MrHzq/vue-router-auto.svg?branch=master)](https://travis-ci.org/MrHzq/vue-router-auto) [![Coverage Status](https://coveralls.io/repos/github/MrHzq/vue-router-auto/badge.svg?branch=master)](https://coveralls.io/github/MrHzq/vue-router-auto?branch=master) 4 | 5 | [GitHub 源码](https://github.com/MrHzq/vue-router-auto) 6 | 7 | [npm 包](https://www.npmjs.com/package/vue-router-auto) 8 | 9 | ### [专门写的案例](https://mrhzq.github.io/vue-router-auto-example/example/index.html#/) 10 | 11 | > 功能:将项目文件自动转为相应的路由配置 和`Nuxt`的路由一样,可实现的功能可以参考[这里](https://zh.nuxtjs.org/guide/routing) 12 | 13 | ## vue 路由自动生成插件 14 | 15 | > 将传入的项目目录,自动转为 vue-router 的路由配置,component 使用异步加载 16 | 17 | 安装:`npm i vue-router-auto -s` 18 | 19 | 然后在 src/router/index.js 里面统一处理 20 | 21 | ```js 22 | import Vue from 'vue' 23 | import Router from 'vue-router' 24 | // 引入依赖 25 | import autoRouter from 'vue-router-auto' 26 | 27 | Vue.use(Router) 28 | 29 | let routes = autoRouter({ 30 | // 页面级的.vue存放位置,必传 31 | rc: require.context('@/views', true, /\.vue$/), 32 | // '/'的重定向,可选,默认为'' 33 | redirect: '/test', 34 | // 页面级的.vue存放的文件夹,可选,默认为:views 35 | rootFile: 'views', 36 | }) 37 | export default new Router({ routes }) 38 | 39 | ``` 40 | 41 | ## 基础路由 42 | 43 | ### 假设 views 的目录结构如下: 44 | 45 | ```js 46 | views/ 47 | --| login.vue 48 | --| home.vue 49 | --| user/ 50 | -----| index.vue 51 | -----| edit.vue 52 | -----| info.vue 53 | ``` 54 | 55 | ### 那么,vue-router-auto 自动生成的路由配置如下: 56 | 57 | ```js 58 | [ 59 | { 60 | name:'login', 61 | path:'/login', 62 | component: () => import('@/views/login.vue') 63 | }, 64 | { 65 | name:'home', 66 | path:'/home', 67 | component: () => import('@/views/home.vue') 68 | }, 69 | { 70 | name:'user', 71 | path:'/user', 72 | component: () => import('@/views/user/index.vue') 73 | }, 74 | { 75 | name:'user-info', 76 | path:'/user/info', 77 | component: () => import('@/views/user/info.vue') 78 | }, 79 | { 80 | name:'user-edit', 81 | path:'/user/edit', 82 | component: () => import('@/views/user/edit.vue') 83 | } 84 | ] 85 | ``` 86 | 87 | ## 嵌套路由 88 | 89 | 创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个**与该文件同名**的目录用来存放子视图组件。 90 | 91 | ### 假设 views 的目录结构如下: 92 | 93 | ```js 94 | views/ 95 | --| login.vue 96 | --| home.vue 97 | --| home/ 98 | -----| index.vue 99 | -----| about.vue 100 | -----| product.vue 101 | --| user/ 102 | -----| index.vue 103 | -----| info.vue 104 | 105 | ``` 106 | 107 | ### 那么,vue-router-auto 自动生成的路由配置如下: 108 | 109 | ```js 110 | [ 111 | { 112 | name:'login', 113 | path:'/login', 114 | component: () => import('@/views/login.vue') 115 | }, 116 | { 117 | path:'/home', 118 | component: () => import('@/views/home.vue'), 119 | children:[ 120 | { 121 | name:'home-index', 122 | path:'', 123 | component: () => import('@/views/home/index.vue') 124 | }, 125 | { 126 | name:'home-about', 127 | path:'about', 128 | component: () => import('@/views/home/about.vue') 129 | }, 130 | { 131 | name:'home-product', 132 | path:'product', 133 | component: () => import('@/views/home/product.vue') 134 | } 135 | ] 136 | }, 137 | { 138 | name:'user', 139 | path:'/user', 140 | component: () => import('@/views/user/index.vue') 141 | }, 142 | { 143 | name:'user-info', 144 | path:'/user/info', 145 | component: () => import('@/views/user/info.vue') 146 | } 147 | ] 148 | ``` 149 | 150 | ## 动态嵌套路由 151 | 152 | ### 假设 views 的目录结构如下: 153 | 154 | ```js 155 | views/ 156 | --| login.vue 157 | --| home.vue 158 | --| home/ 159 | -----| _id.vue 160 | -----| about.vue 161 | --| user/ 162 | -----| user-edit.vue 163 | 164 | ``` 165 | 166 | ### 那么,vue-router-auto 自动生成的路由配置如下: 167 | 168 | ```js 169 | [ 170 | { 171 | name:'login', 172 | path:'/login', 173 | component: () => import('@/views/login.vue') 174 | }, 175 | { 176 | name:'home', 177 | path:'/home', 178 | component: () => import('@/views/home.vue'), 179 | children:[ 180 | { 181 | name:'home-id', 182 | path:':id', 183 | component: () => import('@/views/home/_id.vue') 184 | }, 185 | { 186 | name:'home-about', 187 | path:'about', 188 | component: () => import('@/views/home/about.vue') 189 | } 190 | ] 191 | }, 192 | { 193 | name:'user-edit', 194 | path:'/user/edit', 195 | component: () => import('@/views/user/user-edit.vue') 196 | } 197 | ] 198 | ``` 199 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | declare const _default: (config: any) => any; 2 | /** 3 | * rc:require.context 传入的文件 4 | * redirect:需要将根路由(/)重定向到的路由 5 | * rootFile:页面级别的.vue存放的文件名称 6 | */ 7 | export default _default; 8 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | * @Author: hzq 4 | * @Date: 2018-12-12 10:10:19 5 | * @Last Modified by: hzq 6 | * @Last Modified time: 2019-08-02 15:48:36 7 | * @文件说明: 所有路由处理 - 源码 8 | */ 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | // 所生成的所有路由数组 11 | var Routers = []; 12 | /** 13 | * rc:require.context 传入的文件 14 | * redirect:需要将根路由(/)重定向到的路由 15 | * rootFile:页面级别的.vue存放的文件名称 16 | */ 17 | exports.default = (function (config) { 18 | var defaultConfig = { 19 | rc: null, 20 | redirect: '', 21 | rootFile: 'views' 22 | }; 23 | var _a = Object.assign({}, defaultConfig, config), rc = _a.rc, redirect = _a.redirect, rootFile = _a.rootFile; 24 | if (rc === null) 25 | return Routers; 26 | // allRouters[object]:存储所有路由的变量:先将所有的路由生成,然后放在该变量里面 27 | var allRouters = {}; 28 | // 通过循环RC(传入的文件) 29 | var routerFileAndLen = rc 30 | .keys() 31 | .map(function (fileName) { 32 | // 因为得到的filename格式是: './baseButton.vue', 所以这里我们去掉头和尾,只保留真正的文件名 33 | var realFileName = fileName 34 | .replace(/^\.\//, '') 35 | .replace(/\.\w+$/, ''); 36 | return { 37 | fileName: realFileName, 38 | // routerName(路由名称):将 / 转为 - 并去掉 _ 39 | routerName: realFileName.replace(/\//g, '-').replace(/_/g, ''), 40 | // routerComponent(路由异步component的文件路径):将 ./baseButton.vue 从 . 之后截取 41 | routerComponent: fileName.substr(1), 42 | // fileLen(文件的层级深度):通过 / 的数量来判断当前文件的深度 43 | fileLen: fileName.match(/\//g).length 44 | }; 45 | }) 46 | .sort(function (i, j) { return i.fileLen - j.fileLen; }); // 通过文件深度 升序排序 47 | // 传入文件中最大深度 48 | var maxLen = 0; 49 | routerFileAndLen.map(function (r) { 50 | var name = r.routerName; 51 | // 生成一块路由对象,包含:name、fileName(用于后续处理真正path的依据)、path、needDelectName(用于后续处理,判断是否删除name的依据)、component 52 | var obj = { 53 | name: name, 54 | fileName: r.fileName, 55 | // path:只是以name命名的path,还不是真正的路由path 56 | path: '/' + (name === 'index' ? '' : name), 57 | // needDelectName: name === 'index', 58 | needDelectName: false, 59 | component: function () { return Promise.resolve().then(function () { return require("@/" + rootFile + r.routerComponent); }); } 60 | }; 61 | maxLen = r.fileLen; 62 | // allRouters的key:以 'len'加当前的文件深度 作为key 63 | var key = 'len' + maxLen; 64 | if (Array.isArray(allRouters[key])) 65 | allRouters[key].push(obj); 66 | else 67 | allRouters[key] = [obj]; 68 | }); 69 | // 将根目录层的路由放入Routers中 70 | Routers.push.apply(Routers, allRouters.len1); 71 | // 截取名称方法:从开始到最后一个'-'之间的字符串 72 | var substrName = function (name) { return name.substr(0, name.lastIndexOf('-')); }; 73 | /** 74 | * 正式生成路由:1、将相应的路由放在对应的路由下,形成子路由;2、生成同级路由 75 | * index:当前文件深度,为maxlen的倒序循环 76 | * nofindnum:未找到路由的次数 77 | * newcurr:当前新的深度下的路由数据 78 | */ 79 | var ceateRouter = function (index, nofindnum, newcurr) { 80 | if (nofindnum === void 0) { nofindnum = 0; } 81 | if (newcurr === void 0) { newcurr = null; } 82 | // 当前深度下的路由数据:优先使用传入的newcurr,其次获取当前深度对应的路由数据 83 | var curr = newcurr || allRouters['len' + index]; 84 | // 当前深度上一层的路由数据 85 | var pre = allRouters['len' + (index - 1)]; 86 | // 若 没有上一层的数据了 87 | if (!pre) { 88 | // 则表明是属于顶层的路由 89 | curr.map(function (c) { 90 | var path = '/' + c.fileName.replace('/index', ''); 91 | if (path.match('_')) 92 | path = path.replace('/_', '/:'); 93 | // 将真正的路由path赋值给当前路由 94 | c.path = path; 95 | // 将当前路由放到Routers里面 96 | Routers.push(c); 97 | }); 98 | return; 99 | } 100 | // 在上一层中 未找到的 当前深度路由数据 101 | var noFind = []; 102 | // 循环当前深度路由数据 103 | curr.map(function (c) { 104 | // 在 上一层深度 的路由数据里面查找 105 | var fobj = pre.find(function (p) { 106 | // 生成 当前深度 当前项 路由的name 107 | var name = substrName(c.name); 108 | // 循环nofindnum,当nofindnum>0,则表示已经出现:在上一层中未找到对应的父路由,则需要将 当前深度 当前项 路由的name 再次生成 109 | for (var i = 0; i < nofindnum; i++) { 110 | name = substrName(name); 111 | } 112 | return name === p.name; 113 | }); 114 | // 如果 找到了 对应的 父路由数据(fobj) 115 | if (fobj) { 116 | // 生成 当前路由的path:1、去掉当前路由中与父路由重复的;2、去掉/;3、将 _ 转为 :; 117 | var path = c.fileName 118 | .replace(fobj.fileName, '') 119 | .substr(1) 120 | .replace('_', ':'); 121 | if (path.match('/') && !path.match('/:')) { 122 | path = path.replace('/index', ''); 123 | } 124 | if (path === undefined) { 125 | throw new Error("\u627E\u5230\u4E86\u5BF9\u5E94\u7684\u7236\u8DEF\u7531\uFF0C\u4F46\u662F\u751F\u6210\u5B50\u8DEF\u7531\u7684path\u4E3A\u3010undefined\u3011\u4E86"); 126 | } 127 | // 将真正的路由path赋值给当前路由 128 | c.path = path; 129 | // 若:当前路由为 index 130 | if (path === 'index') { 131 | // 1、转为 '' path,'':表明是默认子路由,那父路由就不能存在name属性 132 | c.path = ''; 133 | // 2、将父路由的needDelectName标记为true,表明需要删除它的name 134 | fobj.needDelectName = fobj.needDelectName || true; 135 | } 136 | // 将当前路由放到父路由的children里面 137 | if (Array.isArray(fobj.children)) 138 | fobj.children.push(c); 139 | else 140 | fobj.children = [c]; 141 | } 142 | else 143 | noFind.push(c); // 表明未找到父路由,则先将当前路由的数据放入noFind中存储起来 144 | }); 145 | // 若存在:未找到的路由数据,则再次向上一个层级寻找 146 | if (noFind.length) 147 | ceateRouter(index - 1, ++nofindnum, noFind); 148 | }; 149 | // 倒序循环 最大深度,然后调用生成路由方法 150 | for (var i = maxLen; i > 1; i--) 151 | ceateRouter(i); 152 | // 路由生成完毕了,应该删除 有默认子路由的父路由的name属性 153 | var deleteNameFun = function (arr) { 154 | arr.map(function (r) { 155 | // 删除多余的fileName属性 156 | delete r.fileName; 157 | // 判断是否需要删除name属性 158 | if (r.needDelectName) 159 | delete r.name; 160 | // 判断完毕了,则要删除needDelectName属性 161 | delete r.needDelectName; 162 | // 若 存在子路由 则继续调用deleteNameFun,删除name 163 | if (Array.isArray(r.children)) 164 | deleteNameFun(r.children); 165 | }); 166 | }; 167 | // 调用deleteNameFun,先删除Routers的一级路由的name 168 | deleteNameFun(Routers); 169 | // 若存在重定向的路由,则加入重定向 170 | if (redirect) 171 | Routers.unshift({ path: '/', redirect: redirect }); 172 | // 返回正儿八经的的路由数据 173 | return Routers; 174 | }); 175 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: hzq 3 | * @Date: 2018-12-12 10:10:19 4 | * @Last Modified by: hzq 5 | * @Last Modified time: 2019-08-02 15:48:36 6 | * @文件说明: 所有路由处理 - 源码 7 | */ 8 | 9 | // 所生成的所有路由数组 10 | const Routers: any = [] 11 | 12 | /** 13 | * rc:require.context 传入的文件 14 | * redirect:需要将根路由(/)重定向到的路由 15 | * rootFile:页面级别的.vue存放的文件名称 16 | */ 17 | export default (config: any) => { 18 | interface Config { 19 | rc: any 20 | redirect: string 21 | rootFile: string 22 | } 23 | const defaultConfig: Config = { 24 | rc: null, 25 | redirect: '', 26 | rootFile: 'views' 27 | } 28 | const { rc, redirect, rootFile } = (Object).assign( 29 | {}, 30 | defaultConfig, 31 | config 32 | ) 33 | if (rc === null) return Routers 34 | 35 | // allRouters[object]:存储所有路由的变量:先将所有的路由生成,然后放在该变量里面 36 | const allRouters: any = {} 37 | // 通过循环RC(传入的文件) 38 | const routerFileAndLen = rc 39 | .keys() 40 | .map((fileName: any) => { 41 | // 因为得到的filename格式是: './baseButton.vue', 所以这里我们去掉头和尾,只保留真正的文件名 42 | const realFileName = fileName 43 | .replace(/^\.\//, '') 44 | .replace(/\.\w+$/, '') 45 | return { 46 | fileName: realFileName, 47 | // routerName(路由名称):将 / 转为 - 并去掉 _ 48 | routerName: realFileName.replace(/\//g, '-').replace(/_/g, ''), 49 | // routerComponent(路由异步component的文件路径):将 ./baseButton.vue 从 . 之后截取 50 | routerComponent: fileName.substr(1), 51 | // fileLen(文件的层级深度):通过 / 的数量来判断当前文件的深度 52 | fileLen: fileName.match(/\//g).length 53 | } 54 | }) 55 | .sort((i: any, j: any) => i.fileLen - j.fileLen) // 通过文件深度 升序排序 56 | 57 | // 传入文件中最大深度 58 | let maxLen = 0 59 | 60 | routerFileAndLen.map((r: any) => { 61 | const name = r.routerName 62 | // 生成一块路由对象,包含:name、fileName(用于后续处理真正path的依据)、path、needDelectName(用于后续处理,判断是否删除name的依据)、component 63 | const obj = { 64 | name, 65 | fileName: r.fileName, 66 | // path:只是以name命名的path,还不是真正的路由path 67 | path: '/' + (name === 'index' ? '' : name), 68 | // needDelectName: name === 'index', 69 | needDelectName: false, 70 | component: () => import(`@/${rootFile}${r.routerComponent}`) 71 | } 72 | maxLen = r.fileLen 73 | // allRouters的key:以 'len'加当前的文件深度 作为key 74 | const key = 'len' + maxLen 75 | if (Array.isArray(allRouters[key])) allRouters[key].push(obj) 76 | else allRouters[key] = [obj] 77 | }) 78 | 79 | // 将根目录层的路由放入Routers中 80 | Routers.push(...allRouters.len1) 81 | 82 | // 截取名称方法:从开始到最后一个'-'之间的字符串 83 | const substrName = (name: any) => name.substr(0, name.lastIndexOf('-')) 84 | 85 | /** 86 | * 正式生成路由:1、将相应的路由放在对应的路由下,形成子路由;2、生成同级路由 87 | * index:当前文件深度,为maxlen的倒序循环 88 | * nofindnum:未找到路由的次数 89 | * newcurr:当前新的深度下的路由数据 90 | */ 91 | const ceateRouter = (index: any, nofindnum = 0, newcurr = null) => { 92 | // 当前深度下的路由数据:优先使用传入的newcurr,其次获取当前深度对应的路由数据 93 | const curr = newcurr || allRouters['len' + index] 94 | // 当前深度上一层的路由数据 95 | const pre = allRouters['len' + (index - 1)] 96 | // 若 没有上一层的数据了 97 | if (!pre) { 98 | // 则表明是属于顶层的路由 99 | curr.map((c: any) => { 100 | let path = '/' + c.fileName.replace('/index', '') 101 | if (path.match('_')) path = path.replace('/_', '/:') 102 | // 将真正的路由path赋值给当前路由 103 | c.path = path 104 | // 将当前路由放到Routers里面 105 | Routers.push(c) 106 | }) 107 | return 108 | } 109 | 110 | // 在上一层中 未找到的 当前深度路由数据 111 | let noFind: any = [] 112 | 113 | // 循环当前深度路由数据 114 | curr.map((c: any) => { 115 | // 在 上一层深度 的路由数据里面查找 116 | const fobj = pre.find((p: any) => { 117 | // 生成 当前深度 当前项 路由的name 118 | let name = substrName(c.name) 119 | // 循环nofindnum,当nofindnum>0,则表示已经出现:在上一层中未找到对应的父路由,则需要将 当前深度 当前项 路由的name 再次生成 120 | for (let i = 0; i < nofindnum; i++) { 121 | name = substrName(name) 122 | } 123 | 124 | return name === p.name 125 | }) 126 | // 如果 找到了 对应的 父路由数据(fobj) 127 | if (fobj) { 128 | // 生成 当前路由的path:1、去掉当前路由中与父路由重复的;2、去掉/;3、将 _ 转为 :; 129 | 130 | let path = c.fileName 131 | .replace(fobj.fileName, '') 132 | .substr(1) 133 | .replace('_', ':') 134 | if (path.match('/') && !path.match('/:')) { 135 | path = path.replace('/index', '') 136 | } 137 | if (path === undefined) { 138 | throw new Error( 139 | `找到了对应的父路由,但是生成子路由的path为【undefined】了` 140 | ) 141 | } 142 | 143 | // 将真正的路由path赋值给当前路由 144 | c.path = path 145 | 146 | // 若:当前路由为 index 147 | if (path === 'index') { 148 | // 1、转为 '' path,'':表明是默认子路由,那父路由就不能存在name属性 149 | c.path = '' 150 | // 2、将父路由的needDelectName标记为true,表明需要删除它的name 151 | fobj.needDelectName = fobj.needDelectName || true 152 | } 153 | // 将当前路由放到父路由的children里面 154 | if (Array.isArray(fobj.children)) fobj.children.push(c) 155 | else fobj.children = [c] 156 | } else noFind.push(c) // 表明未找到父路由,则先将当前路由的数据放入noFind中存储起来 157 | }) 158 | 159 | // 若存在:未找到的路由数据,则再次向上一个层级寻找 160 | if (noFind.length) ceateRouter(index - 1, ++nofindnum, noFind) 161 | } 162 | // 倒序循环 最大深度,然后调用生成路由方法 163 | for (let i = maxLen; i > 1; i--) ceateRouter(i) 164 | 165 | // 路由生成完毕了,应该删除 有默认子路由的父路由的name属性 166 | const deleteNameFun = (arr: any) => { 167 | arr.map((r: any) => { 168 | // 删除多余的fileName属性 169 | delete r.fileName 170 | // 判断是否需要删除name属性 171 | if (r.needDelectName) delete r.name 172 | // 判断完毕了,则要删除needDelectName属性 173 | delete r.needDelectName 174 | // 若 存在子路由 则继续调用deleteNameFun,删除name 175 | if (Array.isArray(r.children)) deleteNameFun(r.children) 176 | }) 177 | } 178 | // 调用deleteNameFun,先删除Routers的一级路由的name 179 | deleteNameFun(Routers) 180 | 181 | // 若存在重定向的路由,则加入重定向 182 | if (redirect) Routers.unshift({ path: '/', redirect }) 183 | // 返回正儿八经的的路由数据 184 | return Routers 185 | } 186 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-router-auto", 3 | "version": "2.0.0", 4 | "description": "自动生成Vue路由", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "test": "mocha --reporter spec", 10 | "cover": "istanbul cover node_modules/mocha/bin/_mocha test/*.js -- -R spec" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/MrHzq/vue-router-auto.git" 15 | }, 16 | "keywords": [ 17 | "vue-router", 18 | "auto-create-vue-router" 19 | ], 20 | "readme": "使用手册https://github.com/MrHzq/vue-router-auto", 21 | "readmeFilename": "README.md", 22 | "author": "hzq", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/MrHzq/vue-router-auto/issues" 26 | }, 27 | "homepage": "https://github.com/MrHzq/vue-router-auto#readme", 28 | "devDependencies": { 29 | "chai": "^4.2.0", 30 | "coveralls": "^3.0.5", 31 | "istanbul": "^0.4.5", 32 | "mocha": "^6.2.0", 33 | "typescript": "^3.5.3" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const expect = require('chai').expect 3 | const index = require('../dist/index.js') 4 | 5 | describe('index', () => { 6 | it('结果:为数组', () => { 7 | const r = index.default() 8 | expect(r).to.be.a('array') 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", // 指定ECMAScript目标版本 4 | "lib": ["es2015", "dom"], 5 | "module": "commonjs", // 指定模块化类型 6 | "declaration": true, // 生成 `.d.ts` 文件 7 | "outDir": "./dist", // 编译后生成的文件目录 8 | "strict": true // 开启严格的类型检测 9 | } 10 | } 11 | --------------------------------------------------------------------------------