美文网首页
Vue路由自动化配置-支持路由嵌套

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

作者: So_da96 | 来源:发表于2020-04-23 16:51 被阅读0次

尝试了两种方案

  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

相关文章

网友评论

      本文标题:Vue路由自动化配置-支持路由嵌套

      本文链接:https://www.haomeiwen.com/subject/nvbaihtx.html