@TOC
在中大型项目中,每次新建页面都要去router文件中添加对应的router对象,会觉得特别麻烦,而且多人开发还不好方便维护,甚至当router层级发生变化的时候,可能要重写整个router对象数组,因此我们需要一个自动化router
自动化router的最大好处:前端只需要专注写代码即可,无需关注路由的router文件中的router.js
在vue中,router.js必须的写法
{
path: 'login',
name: 'login',
component: () => import('./views/Login')
},
因此我们只需要拿到import导入的文件路径,然后设置它的path和name即可
重点是拿到文件路径,我们有两种方式可以自动拿到文件路径,因此我们有两种实现自动化路由的方法:
1、通过node 拿到文件的路径,
2、通过webpack的require.context() 方法拿到文件的路径
我们分别从两种方式来实现自动化router
在node中,我们可以用fs和path两个方法来获取文件路径
var fs = require('fs')
const path = require('path')
我们在config下建立一个router.js文件
利用递归方法,输出一个router.json,文件名组成的数组
// config.router.js
var fs = require('fs')
const path = require('path')
const config = require('./index')
const result = []
const readdir = (pagesPath, fileLevel = []) => {
const _dir = path.join(__dirname, pagesPath)
fs.readdirSync(_dir).forEach(fileName => {
const state = fs.lstatSync(_dir + '/' + fileName)
if (state.isDirectory()) { // 如果是目录就往下找
readdir(pagesPath + '/' + fileName, fileLevel.concat(fileName))
} else if (/.vue/.test(fileName)) { // 如果是vue文件,则输出
result.push(fileLevel.concat(fileName))
}
})
}
// 输出文件配置
readdir(config.router.pagesPath)
fs.writeFile(path.join(__dirname, '../src/router/router.json'), JSON.stringify(result), function (err) {
if (!err) {
console.log('===================')
console.log('router.json 配置完毕')
console.log('===================')
}
})
/*输出结果如下
[["Index.vue"],["errer","Index.vue"],["home","Index.vue"],["mine","Edit.vue"],["mine","Index.vue"],["mine","editPSW","Index.vue"],["mine","info","Index.vue"]]
*/
对比输出的json和我们文件对比一下
[
["Index.vue"],
["errer","Index.vue"],
["home","Index.vue"],
["mine","Edit.vue"],
["mine","Index.vue"],
["mine","editPSW","Index.vue"],
["mine","info","Index.vue"]
]
|-- pages
|-- errer
|-- Index.vue
|-- home
|-- Index.vue
|-- mine
|-- editPSW
|-- Index.vue
|-- info
|-- Index.vue
|-- Edit.vue
|-- Index.vue
|-- Index.vue
通过对比,我们可以得到包含.vue文件的名字和到pages下其父级文件的所有名字
我们在main.js已经注册router,因此我们在src的router文件夹下创建一个initRouter.js,此js主要做如下的功能
// src.router.initRouter.js
import importComponent from '../common/lib/importComponent' //自动化引入组件
export default (pageName = 'index') => {
const routerConfig = require('./router.json')
// 获取页面的路径
const getPagePath = (connector = '/') => {
return pageName === 'index' ? '' : `${pageName}${connector}`
}
// 处理文件路径名称
const filePath = (fileLevel) => {
let fl = JSON.parse(JSON.stringify(fileLevel))
return fl.join('/')
}
// 获取组件名称
const getImportComponentNames = (defaultFileLevel) => {
return `pages/${filePath(defaultFileLevel)}`
}
const initRoutes = (fileList) => {
const _list = []
fileList.forEach((fileLevel, index) => {
if (fileLevel[0] !== 'fusion' && fileLevel.length < 2) {
return
}
const defaultFileLevel = JSON.parse(JSON.stringify(fileLevel)) // 复制原始ITEM 防止被污染
const file = fileLevel.pop()
let fileName = file.split('.')[0]
fileName = fileName.substring(0, 1).toLowerCase() + fileName.substring(1)
const obj = {}
if (fileName.toLowerCase() !== 'index') {
fileLevel = fileLevel.concat(fileName)
} else {
obj.alias = `/${getPagePath()}${filePath(fileLevel)}/index`
}
const routerPath = `/${getPagePath()}${filePath(fileLevel)}`
const routerName = `${getPagePath('_')}${fileLevel.join('_')}`
_list.push({
...obj,
path: routerPath,
name: routerName,
index: index,
defaultFileLevelList: defaultFileLevel,
componentNames : getImportComponentNames(defaultFileLevel),
component: importComponent(getImportComponentNames(defaultFileLevel), (Module) => {
Module.default.name = routerName
})
})
})
return _list
}
return initRoutes(routerConfig)
}
我们在router文件下的index.js,
此时把我们自动化生成的数组放在new Router里即可就可以实现一个自动化路由的配置
// src.router.index.js
import getRouter from './initrouter'
import Vue from 'vue'
import Router from 'vue-router'
import resetRouterPush from '../common/lib/resetRouterPush'
resetRouterPush(Router)
Vue.use(Router)
const children = getRouter()
const router = new Router({
mode: 'history',
routes: [{
path: '/',
name: 'pages_Index',
component: () => import('@/pages/Index'),
redirect: '/home',
children
},
{//当跳转路径写错的时候,我们可以设置回到首页、或者到自定义404页面
path: '*',
redirect: '/errer'
}
]
})
export default router
最后我们在终端输出
node config/router
终端显示
![]()
此时在运行环境即可
扩展
webpack提供了一个api:require.context()
写法如下
require.context(directory,useSubdirectories,regExp)
const routeFiles = require.context('@/pages', true, /\.vue/)
console.log(routeFiles)
通过使用require我们可以很容易的得到我们pages 下的全部vue文件的路径,因此他比node使用起来还要简介,方便。
打印,我们可以看到,我们已经拿到相对路径,并放在keys里面
我们只需在src/router/index.js文件里
// router/index.js
import Vue from 'vue';
import vueRouter from 'vue-router'
Vue.use(vueRouter);
const getRouterName = (name)=>{
name = name.substring(1,name.length)
return name.split('/').join('_')
}
// // 查找 pages 下的全部vue文件
const routeFiles = require.context('@/pages', true, /\.vue/)
let children = []
routeFiles.keys().forEach(item => {
let path = JSON.parse(JSON.stringify(item))
if(/\/Index.vue/.test(path)){//path去除index根文件名
path = path.substring(0,path.length - 10)
}
if (path !== '.') { //因为父亲是的路径在/pages/Index下,因此我们不需要注册改router
let info = path.split('.')
children.push({
path: info[1],
name: getRouterName(info[1]),
component: routeFiles(item).default
})
}
})
const router = new vueRouter({
mode: 'history',
routes: [{
path: '/',
name: 'pages_Index',
component: () => import('@/pages/Index'),
redirect: '/home',
children
},
{//当跳转路径写错的时候,我们可以设置回到首页、或者到自定义404页面
path: '*',
redirect: '/errer'
}
]
})
export default router;