查看原文
其他

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

前端技术 OPPO数智技术 2021-10-05

在开发管理端系统时,基于页面目录生产的路由的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目录结构
componentimport('pages/user.vue')
path"pages/user":文件路径(去掉.vue)
namepath.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、排列顺序等,但是,这些信息如何存放呢?

  1. 存放在文件命名,文件命名会很长很怪,显然不合适,no

  2. 存放在文件内容中,并能通过特定格式解析出来结构,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自研ESA DataFlow架构与实践

数据同步一致性保障:OPPO自研JinS数据同步框架实践

更多技术干货

扫码关注

OPPO互联网技术

 

我就知道你“在看”
: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存