约定式路由的菜单数据生成方案
在开发管理端系统时,基于页面目录生产的路由的routes是一个比较流行和省事的方案,但是,能不能再省点事,随便把菜单数据也一并生成呢?
基于这个问题,本文主要介绍CookJS,它可以理解成Vue CLI,是OPPO内部自研可插拔的企业级 Vue@ 应用框架,提供了构建、编码、打包等功能。
1. 目录与路由
约定式路由,也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。目前许多开源框架都支持,比如:UmiJS、Nuxt.js、vue-auto-routing等等。
CookJS参考了Nuxt.js的约定式路由规范,内置支持了约定式路由。下面讲解CookJS的约定式路由的一些概念。
1.1 基础路由
假设 pages 的目录结构如下:
.
├── index.vue
└── user
├── id.vue
└── index.vue
那么,CookJS 自动生成的路由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 动态路由
在 CookJS 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 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 的子路由创建 cookjs 应用的嵌套路由。
创建内嵌子路由,你需要添加一个 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.vue中template要包含<router-view> |
2. 路由与菜单
菜单和路由都是一种树的结构,我们先来看看一个简单菜单数据格式:
[
{
"index": "菜单ID",
"title": "菜单名",
"iconClass": "菜单icon",
"sort": "菜单排序",
"router": "vue-router的路由对象",
"children": ['...']
},
'....'
]
2.1 菜单和目录对应
目录和菜单的数据直接一一对应(未做文案定制的效果)
路由中字段的值都是可以通过目录的层级和文件命名推算,但是,菜单需要有一些定制化的内容,比如:菜单名、菜单Icon、排列顺序等,但是,这些信息如何存放呢?
存放在文件命名,文件命名会很长很怪,显然不合适,no
存放在文件内容中,并能通过特定格式解析出来结构,yes
菜单信息借助了CookJS扩展> 路由元信息,即是扩展 vue单文件组件中自定义代码块 <route-meta> 来存放菜单信息。
2.2 meta扩展
vue单文件组件除了<template>、<script>和<style>这些语法块,还支持自定义语法块的。
CookJS扩展的路由元信息,源码解析如何扩展 <route-meta> ,vue单文件组件(pages/index.vue)内容如下:
// 单文件组件扩展route-meta
<route-meta>
export default {
$layout: {
name: '首页',
icon: 'co-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 解析代码,具体代码如下:
然后将 解析自定义语法块的内容写进 .cook/router/meta/index.js文件中。最终被 .cook/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字段绑定就已经实现了。
一个菜单对应多个路由的这种关系是比较常见的场景,比如,从列表页进入详情页时,路由虽然变化,但是系统的菜单还要保持一样。(观察url和基础列表菜单)
菜单:基础列表对应了 /infoList/basic 和 /infoList/basic/hide这两个路由,即一个菜单对应两个路由。
CookJS通过嵌套路由并结合 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中的路由元信息中就可以提取出菜单数据了。
3. 总结
约定式路由和vue单文件组件扩展(route-meta)自定义语法块,实现一套菜单、路由和目录的规范,除了节省了编写路由的代码,更重要的是在这种清晰的目录组织和代码编写方式,直接通过URL就可以定位到页面代码,在开发查问题的时候,也就变得十分简单。
☆ END ☆
OPPO互联网技术团队招聘一大波岗位,涵盖C++、Go、OpenJDK、Java、DevOps、Android、ElasticSearch等多个方向,请点击这里查看详细信息及JD。
更多技术干货
扫码关注
OPPO互联网技术