Vue路由自动化配置-支持路由嵌套

尝试了两种方案

  1. 方案一(推荐)注意配置规则
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
})

  1. 方案二 监听文件的新增与删除,生成路由文件
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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值