尝试了两种方案
- 方案一(推荐)注意配置规则
import Vue from 'vue'
import Router from 'vue-router'
import loginLayout from '@/layout/Login.vue'
import mainLayout from '@/layout/Main.vue'
const requireComponent = require.context('@/views', true, /\.vue$/)
var routes = [{
path: '/login',
name: 'login',
component: loginLayout,
children: []
}]
// 主页面框架,所有自动配置的路由都放到此处
const mainLayoutRouter = {
path: '/',
component: mainLayout,
redirect: '/home',
children: []
}
// 路由自动化注册
// important!!!!!匹配规则:子路由在页面中配置parent字段指定父路由名称(路径,/转-,所有大写转小写)
try {
// 记录所有子路由页面(含parent字段)
const childrenComponents = []
requireComponent.keys().forEach(filePath => {
// 剔除业务组件components文件夹下vue文件
if(filePath.index('components')!==-1){
return
}
const componentConfig = requireComponent(filePath)
const componentItem = componentConfig.default || componentConfig
// if (!componentItem.name) {
// throw new Error(`${filePath} 请添加name字段`)
// }
// const component = Vue.component(componentItem.name, componentItem)
const componentPath = filePath.replace(/^\.\//, '').replace(/\.vue$/, '').toLowerCase()// 剥去文件名开头的 `./` 和`.vue`结尾的扩展名
const componentName = componentPath.replace(/\//g, '-').toLowerCase()
const chunckNames = filePath.replace(/^\.\//, '')
const result = {
path: '/' + componentPath, // home/detail
name: componentName, // home-detail
// component: () => component,
// TODO 设置打包后文件名
component: () => import(/* webpackChunkName: "[request]" */ `@/views/${chunckNames}`),
children: []
}
// 优先添加非子路由页面
if (componentItem.parent) {
childrenComponents.push({ path: componentPath, parentName: componentItem.parent, component: result })
} else {
mainLayoutRouter.children.push(result)
}
})
// 挂载子路由到父路由,若未找到提示parent配置错误
let index = 0
let tempChildcompsLength = childrenComponents.length
while (index < childrenComponents.length) {
const child = childrenComponents[index]
const parent = findParentByName([mainLayoutRouter], child.parentName)
if (parent) {
if (!parent.children) parent.children = []
parent.children.push(child.component)
childrenComponents.splice(index, 1)
} else {
index++
}
// 循环到最后一项,判定childrenComponents是否有变化
// 若没有,说明剩下的页面parent都没有找到
if (index === childrenComponents.length) {
if (tempChildcompsLength !== childrenComponents.length) {
tempChildcompsLength = childrenComponents.length
index = 0
} else {
// 根据parent没有找到父元素
const page404 = childrenComponents.map(it => {
return it.path
})
alert(`页面parent未找到,请检查: \n${page404.join('\n')}`)
}
}
}
} catch (error) {
alert(error.message)
}
/**
* 根据父路由name查找父路由
* @param {Array} routers 需要查找的路由数组
* @param {String} parentName 父组件name
*/
function findParentByName (routers, parentName) {
let parent = null
function findParent (routers, parentName) {
try {
routers.forEach(route => {
if (route.name === parentName) {
parent = route
throw new Error()
} else if (route.children && route.children.length) {
findParent(route.children, parentName)
}
})
} catch (err) {}
}
findParent(routers, parentName)
return parent
}
routes.push(mainLayoutRouter)
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: routes
})
- 方案二 监听文件的新增与删除,生成路由文件
const chokidar = require('chokidar')
const fs = require('fs')
const path = require('path')
class AutoRouter {
/**
* 根据业务页面自动生成路由
* @param {String} watchDir 业务页面路径
* @param {String} templateRouterPath 路由模板文件路径
* @param {String} targetRouterPath 路由生成路径
*/
constructor (watchDir, templateRouterPath, targetRouterPath) {
this.watchDir = watchDir
this.templateRouterPath = templateRouterPath
this.targetRouterPath = targetRouterPath
}
// 初始化
init () {
/**
* 监听文件新增删除,配置路由
* 匹配views文件夹下所有vue文件,排除components业务组件
*/
chokidar.watch(this.watchDir).on('all', (event, path) => {
if (['add', 'unlink'].indexOf(event) !== -1 &&
path.indexOf('.vue') !== -1 &&
path.indexOf('components') === -1
) {
console.log(event, path)
this.autoFactRouter(this.templateRouterPath, this.targetRouterPath)
}
})
}
/**
* 根据模板自动生成路由文件
* @param {*} templatePath 模板路径
* @param {*} targetPath 生成文件路径
*/
autoFactRouter (templatePath, targetPath) {
fs.readFile(templatePath, 'utf-8', (error, data) => {
// 用error来判断文件是否读取成功
if (error) return console.error('读取路由模板失败:' + error.message)
// 读取所有的路由
const files = this.getFilesSync(this.watchDir)
const routerBodys = []
files.forEach(filePath => {
const compPath = filePath.replace(`${this.watchDir}/`, '').replace(/\.vue$/, '')
const result = `{
path: '/${compPath.toLowerCase()}',
name: '${compPath.replace(/\//g, '-').toLowerCase()}',
component: () => import(/* webpackChunkName: "${compPath.toLowerCase()}" */ '${filePath.replace(/src/g, '@')}'),
children: []
}`
routerBodys.push(result)
})
const content = data.replace('<%routers%>', `[${routerBodys.toString()}]`)
fs.writeFile(targetPath, content, (err) => {
if (err) throw err
console.log('路由写入成功')
})
})
}
/**
* 读取文件夹下所有文件、文件夹
* @param {String} fileDir 文件夹路径
*/
getFilesSync (fileDir) {
const fileList = []
this.readDir = (entry) => {
const dirInfo = fs.readdirSync(entry)
dirInfo.forEach(item => {
const location = path.join(entry, item)
const info = fs.statSync(location)
if (info.isDirectory()) {
this.readDir(location)
} else {
fileList.push(location)
}
})
}
this.readDir(fileDir)
return fileList
}
}
module.exports = AutoRouter
router.txt
/**
* 模板自动生成文件,请勿修改
*/
/* eslint-disable */
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes: <%routers%>
})
export default router
网友评论