手把手教你写自动化路由

前言

在中大型项目中,每次新建页面都要去router文件中添加对应的router对象,会觉得特别麻烦,而且多人开发还不好方便维护,甚至当router层级发生变化的时候,可能要重写整个router对象数组,因此我们需要一个自动化router
自动化router的最大好处:前端只需要专注写代码即可,无需关注路由的router文件中的router.js

思路

在vue中,router.js必须的写法

{
	path: 'login',
	name: 'login',
	component: () => import('./views/Login')
},

因此我们只需要拿到import导入的文件路径,然后设置它的pathname即可
重点是拿到文件路径,我们有两种方式可以自动拿到文件路径,因此我们有两种实现自动化路由的方法:
1、通过node 拿到文件的路径,
2、通过webpack的require.context() 方法拿到文件的路径

我们分别从两种方式来实现自动化router

使用node实现自动化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主要做如下的功能

  • 自动化设置router的path
  • 自动化设置router的name
  • 自动化设置router的index
  • 自动化设置router的defaultFileLevelList
  • 自动化设置router的componentNames
  • 自动化设置router的component
// 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

终端显示在这里插入图片描述

此时在运行环境即可

  • 扩展

    • 我们也可以把node命令放到webpack里面,这样子也可以使用npm run 来实现
  • 注意:

    • 每次文件变更时候,必须运行node config/router

使用webpack实现自动化router

webpack提供了一个api:require.context()

写法如下

require.context(directory,useSubdirectories,regExp)

  • 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;
  • 扩展
    • require.context()拿常常拿来写自动化注册全局组件

在这里插入图片描述

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荒男

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值