前言
为了做好这款 Admin,我们累计开发了430+
天、提交了1900+
commit,做了一款和市面上都不一样的 Admin,目标是为了让大家在使用这款系统时少一点加班,多一点时间陪伴家人!!!
技术栈
使用 vite
、vue3
、typescript
、unocss
开发,和市面上所有开源 admin 的架构方案设计都不一样
,真正意义上做到了高内聚
、低耦合
、可扩展
,值得一提的是此套架构方案在让您阅读源码时可以很清晰的看到每一块功能的实现。
预览
因为目前 Admin 的 ui 已经足够成熟,开发者、产品、客户也习惯了,所以这一块我们并没有去做创新的设计,但是在逻辑实现层面做了完全不一样的设计。






痛点
在使用其他后台 Admin 的时候,有没有碰到过以下的问题
后台布局想修改一些功能
:无处下手或者代价很大。后台布局新增
:有的系统已经做的够完善了,甚至提供了7、8
种布局,但是让开发者去新增一套布局,可能会被内部大量的判断劝退
。无法个性化定制菜单
:布局和菜单高度绑定,无法支持类似菜单分组
、ui 设计稿
需求。权限设计高度耦合
:想阅读源码学习一下,可能会漫游在不同的文件中丢失了方向,这些文件中不止包含了权限的设计,可能还会包含其他功能的实现。标签栏扩展能力弱
:想动态修改 tab 信息难、想给列表中的每一条信息都单独开一个 tab 页难、想删除的时候二次确认难、想做一些扩展实现难(数量限制)。路由设计缺陷 1
:要求每一条路由必须要写name
属性,否则无法完成一些功能,但是vue-router
中并没有这么要求。路由设计缺陷 2
:要求嵌套路由(列表->详情)的时候不能嵌套化的书写路由,否则没办法给列表和详情单独定义component
属性,这是vue-router
的限制,因为每一个层级的component
对应一个router-view
,而在 Admin 中基本上都是只有2 个 router-view
。路由设计缺陷 3
:详情页不在菜单中显示,但是需要高亮列表页的菜单项,需要在详情路由中单独定义一些属性去标识你需要高亮的菜单,这其实是因为不能嵌套编写路由所引发的连环问题。路由设计缺陷 4
:扩展路由能力的时候,会在route.meta
上定义一些属性,用户点击每一个meta
,可能只会跳转到全局的.d.ts
中,无法看清这个route.meta
是被谁实现的、怎么实现的。过度封装?
:这点仁者见仁、智者见智,每个开发者都有自己的封装习惯,但是想看一个功能,功能被多层级的套娃不是一个合理的设计
以上这些不是刻意在贬低其他的 Admin,因为我为了方便,也会去使用它们,这是在开发项目时遇到的实际问题。
解决方案
以上的痛点我们总结归类一下,分为几大块
路由设计
:如何设计成可扩展、可维护的布局设计
:如何设计成可扩展、可维护的菜单设计
:如何设计成可扩展、可维护的
以上几块的设计几乎贯穿了 Admin 架构的所有功能,我们一个一个聊。
路由的插件化设计
路由想设计成可扩展、可维护的,插件化的架构设计才能做到这一点!我们在 Admin 中定义了一个子包 @pro/router
,它的使用方式和 vue-router
完全一致,只不过我们做了额外的扩展,多了一个 plugins
属性,我们向外暴露了 Admin 系统所需要的全部插件,你可以按需引用、渐进式扩展功能,如图

以上的每一个插件都单独实现一个功能,插件和插件之间不存在联动关系,所以你可以按需引用,这里我们拿一个简单的 breadcrumbPlugin
面包屑插件举例,如图

面包屑的数据很容易被我们组装出来,如何提供给外界对应的组件使用呢?我们可以在 router
上自定义字段,如图

外界如下使用即可

是不是挺简单呢?一个插件对应一个功能,我们的 Admin 就是按照搭积木
的方式组装而成,由于篇幅有限,更多的插件实现大家可以在文章底部查看对应源码或者文档。
布局的策略模式设计
布局组件不一定会被用在 Admin 系统中,所以我们把它放进了基于 naive-ui 封装的高级组件库 pro-naive-ui 中,顺便简单介绍一下,pro-naive-ui
也是完全开源的,对表单
、表格
、大量组件
做了高级封装,真正能落地在企业级项目中
。
说回正题,现在的布局组件支持 7种
布局模式,当然也支持移动端模式
,布局组件支持大量的属性和插槽,如图

我们在 Admin 中如下图使用

对于有很多种布局模式,内部如何避免掉大量的 if else
之类的判断呢?策略模式可以做到这一点,我们只需要对每种不同的布局模式应用不同的 css
即可。如图:

通过策略模式,我们在未来可以很轻松的继续扩展布局! 问题来了,用户如何能在不依赖布局组件的情况下继续扩展布局呢?比如想个性化的自定义布局,如图

答案我们在菜单的无头能力设计
中揭晓!
菜单的无头能力设计
布局组件帮我们解决了 css
问题,然而在 Admin 中布局组件下往往会包含多个菜单,多个菜单之间还会根据一些属性去做一些联动行为,这里的菜单指的不一定是 n-menu
,可能还会有上面提到的个性化菜单
,如果单独把 n-menu
封装一下,可能很难去满足各种个性化场景的需求,所以我们将这种多个菜单进行联动的场景抽象成了一个 composable
,它与 ui
无关,它专注于解决菜单之间的联动问题,然后将处理好的菜单数据交给外层,外层可以直接消费这个数据传递给对应的菜单组件,在我们的 Admin 中是这么使用的

内部会根据完整的 menus
数据以及 mode
属性自动分割相关菜单,layout 中的数据可以被菜单直接消费,除了 layout
属性,它还导出了以下属性

而完成以上个性化的菜单
功能,我们只需要取暴露出来的 mixedSidebarLayout
属性即可实现联动,由于篇幅有限,也不是整体文章的重点,所以代码我们暂且略过。。。
多页签的拦截器模式设计
多页签也是布局设计中的一环,他们一般长这样

如果你看过其他 Admin 多页签的实现,你可能会感慨一句"设计的好复杂",想做一些扩展难度比较大。之所以复杂难扩展是因为内部涉及了很多功能扭转,比如固定状态下无法被删除
、给用户预留了新的 title 属性
等等之类的判断。
我们将多页签设计成了一个路由插件
,因为多页签代表的是访问过的路由记录列表,我们将它命名为 visitedRoutesPlugin
。
我们如何满足用户的特定场景呢?答案就是拦截器模式
,路由记录列表实则就是一个数组,我们只需要对这个数组的增
、删
、移
做拦截即可,代码如下

可以看到代码很简单,就是在增
、删
、移
做了前置拦截
和后置通知
,除了这些操作外,还需要一个当前高亮的索引
记录正在访问的路由,它的实现也很简单,因为它本身也可以基于拦截器模式,代码如下

那用户想实现个性化的场景怎么完成?我们可以向外导出这些拦截器,如下

以上几乎能满足用户的各种个性化需求,我们简单举几个例子,完整例子请参考我们 Admin 中 Demo 示例
场景一:自定义 title
用户可能想在添加多页签的时候自定义 title
,可以如下编写

场景二:单独的页签
用户可能想给表格中的每一行数据跳转去详情的时候单独开一个页签,可以如下编写

相关链接
- 预览地址:naive-ui-pro.pro-components.cn/
- github 地址:github.com/Zheng-Chang...
- pro-naive-ui 文档地址:naive-ui.pro-components.cn/
- pro-naive-ui github 地址:github.com/Zheng-Chang...
最后
篇幅有限,一篇文章很难说清楚每个功能的实现细节,说的不对之处还请指正!
项目上线不久,我们欢迎并感谢所有形式的贡献。如果您有任何想法或建议,欢迎通过提交 pull requests
或创建 issue
来分享。