约定式路由的菜单数据生成方案

3,751 阅读4分钟

本文是azuo和萌妹俩的第二篇创作,内容创作@azuo😄,精神支持@大头萌妹😂

前言:在开发管理端系统时,基于页面目录生产的路由的routes是一个比较流行和省事的方案,但是,能不能再省点事,随便把菜单数据也一并生成呢?

一、目录与路由

约定式路由,也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。目前许多开源框架都支持,比如:UmiJSNuxt.jsvue-auto-routing等等。

Nuxt.js的约定式路由规范作为讲解示例。

1.1、基础路由

假设 pages 的目录结构如下:

.
├── index.vue
└── user
    ├── id.vue
    └── index.vue

那么,自动生成的路由routes.js,内容如下:

[ {   
  path: '/user',    
  name: 'user-index',    
  component: () => import('@/pages/user/index.vue'),
 },{    
  path: '/user/id',    
  name: 'user-id',    
  component: () =>import('@/pages/user/id.vue') 
 },{    
   path: '/',    
   name: 'index',    
   component: () => import('@/pages/index.vue'),
 }]

1.2、动态路由

定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。

将:pages/user/id.vue 改名为:pages/user/_id.vue

.
├── index.vue
└── user
    ├── _id.vue
    └── index.vue

生成对应的路由配置表为:

// routes
[ {   
  path: '/user',    
  name: 'user-index',    
  component: () => import('@/pages/user/index.vue'),
 },{    
  path: '/user/:id',  // 动态路由   
  name: 'user-id',    
  component: () =>import('@/pages/user/id.vue') 
 },{    
   path: '/',    
   name: 'index',    
   component: () => import('@/pages/index.vue'),
 }]

1.3 嵌套路由

你可以通过 vue-router 的子路由来生产的嵌套路由。

创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。

增加一个 pages/user.vue 文件,目录结构如下:

.
├── index.vue
├── user
│   ├── id.vue
│   └── index.vue
└── user.vue # template需包含router-view

那么,生成对应的路由配置表为:

// routes
[{
  path: '/user',    
  name: 'user',   
  component: () => import('@/pages/user.vue'),
  children: [
    {        
     path: '',       
     name: 'user-index',        
     component: () => import('@/pages/user/index.vue'),
    },{
     path: 'id',        
     name: 'user-id',       
     component: () => import('@/pages/user/id.vue'),
    }    
  ]
 }, {    
  path: '/',    
  name: 'index',   
  component: () => import('@/pages/index.vue'),
}]

1.4、实现总结

以目录中 pages/user.vue,作为说明示例:

.
├── index.vue
├── user
│   ├── id.vue
│   └── index.vue
└── user.vue

vue-router中routes字段所需要的值,如下

vue-router字段pages目录结构
componentimport('pages/user.vue')
path"pages/user":文件路径(去掉.vue)
namepath.replace(//g,'-')
childrenuser.vue单文件和user目录同名,即开启嵌套路由,user目录的内容即为children字段的值,注意,user.的template 要包含<router-view>

二、路由与菜单

菜单和路由都是一种树的结构,我们先来看看一个简单菜单数据格式:

[
  {
    "index": "菜单ID",
    "title": "菜单名",
    "iconClass": "菜单icon",
    "sort": "菜单排序",
    "router": "vue-router的路由对象",
    "children": ['...']
  },
  '....'
]

2.1 菜单和目录对应

目录和菜单的数据直接一一对应(未做文案定制的效果)

路由中字段的值都是可以通过目录的层级和文件命名推算,但是,菜单需要有一些定制化的内容,比如:菜单名、菜单Icon、排列顺序等,但是,这些信息如何存放呢?

  • 存放文件命名中:文件命名会很长很怪,显然不合适。No

  • 存放到文件内容中:并能通过特定格式解析出来结构;Yes

菜单信息借助了vue单文件组件中自定义代码块 来存放菜单信息。

2.2 meta扩展

vue单文件组件除了<template>、<script>和<style>这些语法块,还支持自定义语法块的。

扩展vue单文件组件的 **<route-meta>**自定义语法块,vue单文件组件(pages/index.vue)内容如下:

// 单文件组件扩展route-meta
<route-meta>  
  export default {    
    $layout: {      
      name: '首页',      
      icon: 'el-icon-home',      
      index: 0    
    }  
  }
</route-meta>
<template>  
  <div class="wrap">   
    Hi ,CookJS!<br />    
    path: @/pages/index.vue  
  </div>
</template>
<script>
  export default {  
    name: 'PageIndex',
  }
</script>
<style lang="scss" scoped>
  .wrap {  display: flex;}
</style>

借助 vue-template-compiler 解析代码,具体代码如下:

然后将 解析自定义语法块的内容写进 src/router/meta/index.js文件中。最终被 src/router/routes.js 文件引用

完整的 vue-router 的完整数据结构

[ {   
  path: '/user',    
  name: 'user-index',    
  component: () => import('@/pages/user/index.vue'),
  meta:{ 
    $layout: { // 菜单定制文案
      name: '首页',    
      icon: 'co-icon-home',    
      index: 0, 
      disabled: true //是否显示
    }
  }
}]

2.3 菜单一对多

菜单和路由 一对一的关系,通过router中meta字段绑定就已经实现了。一个菜单对应多个路由的这种关系是比较常见的场景,比如,从列表页进入详情页时,路由虽然变化,但是系统的菜单还要保持一样。

通过嵌套路由并结合 route-mate的一对一的关系扩展,来实现菜单和路由的一对多的关系。

先来看看路由数据结构:

[ {   
     path: 'basic',        
     name: 'infoList-basic',        
     component: () => import('@/pages/infoList/basic.vue'),
     meta: {
        $layout: {    
          name: '基础列表',   
          index: 2,    
          registerMenu: { // 一对多实现的关键标识字段
             defalut: 'index' 
          }
        }
     },
     children: [ {
         path: '',            
         name: 'infoList-basic-index',            
         component: () =>import('@/pages/infoList/basic/index.vue'),
         meta: {},          
       },{
         path: 'hide',            
         name: 'infoList-basic-hide',            
         component: () => import('@/pages/infoList/basic/hide.vue'),
         meta: {},          
       }        
     ]
}]

通过识别route-meta中 registerMenu 字段后,将整个嵌套的路由识别成一个菜单,这样,就实现一个菜单对应多个子路由,从而完成一对多的关系实现。从routes中的路由元信息中就可以提取出菜单数据了

三、总结

约定式路由和vue单文件组件扩展(route-meta)自定义语法块,实现一套菜单、路由和目录的规范,除了节省了编写路由的代码,更重要的是在这种清晰的目录组织和代码编写方式,直接通过URL就可以定位到页面代码,在开发查问题的时候,也就变得十分简单。