约定式路由的菜单数据生成方案
前言:在开发管理端系统时,基于页面目录生产的路由的routes是一个比较流行和省事的方案,但是,能不能再省点事,随便把菜单数据也一并生成呢?
一、目录与路由
约定式路由,也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。目前许多开源框架都支持,比如:UmiJS、Nuxt.js、vue-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目录结构 |
---|---|
component | import('pages/user.vue') |
path | "pages/user":文件路径(去掉.vue) |
name | path.replace(//g,'-') |
children | user.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就可以定位到页面代码,在开发查问题的时候,也就变得十分简单。
转载自:https://juejin.cn/post/6891182298701119501