-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
109 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ const dirs = [ | |
"源码解读", | ||
"商业思考", | ||
"算法", | ||
"可视化搭建", | ||
"SQL" | ||
]; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
在做任何可视化搭建项目时,第一步都要思考如何抽象。 | ||
|
||
如果不抽象,当搭建项目做到后期可能会出现 API 杂乱,难以维护的问题;做到一半甚至会怀疑为什么需要一个搭建框架,怀疑把框架去掉会不会效率更高;在后期发现不能自然的水平拓展到仪表盘、大屏、表单搭建场景等。 | ||
|
||
所以如果在维护一套可视化搭建系统时,不管这个系统的上层是 BI、大屏、表单填报,还是脑图也好,无论是什么,都要先思考一下这些系统背后的底层是什么,需不需要抽象,抽象的意义和价值在哪。 | ||
|
||
以下结合笔者的经验,尝试给出一种思考角度。 | ||
|
||
## 精读 | ||
|
||
### 什么是可视化搭建 | ||
|
||
表单搭建、中后台应用搭建、BI 仪表盘搭建、大屏搭建都算可视化搭建,因为它们都是在一个画布上拖拖拽拽完成的。 | ||
|
||
那么组件配置表单算搭建吗?聚焦单组件分析的可视化探索呢?幻灯片呢? | ||
|
||
比如组件配置表单,它基于 UI 组件树抽象的话,就是可视化搭建,但如果基于表单结构抽象,就是 JsonSchema,但真的所有业务场景都是数据完全映射 UI 吗?不一定,因为 UI 可以为了用户操作方便而加入更多辅助元素,甚至把一个属性拆成多个 UI 填写,所以基于可视化搭建,也就是 UI 组件树抽象的一定可以覆盖所有表单场景,但不一定是描述效率最高的方式。 | ||
|
||
如果每种可视化搭建场景都定义一套协议与实现,那按照搭建平台的复杂度,想同时维护两个类搭建平台的成本一定是两倍,而且不同维护人员很难交流。又或者某些可以按照搭建思路解决的场景,因为实现时经验不足,没有进行抽象,甚至进行了另一套定制抽象,回过头来看可能积重难返,团队不得不接受多套笨重实现的现状。 | ||
|
||
所以建议将这些场景都视为可视化搭建场景,用一套接口描述结构、API 方法,让看似百花齐放的编辑器之下拥有统一的上下文与实现。 | ||
|
||
### 可视化搭建的分层 | ||
|
||
对于不同种类的可视化搭建平台,我们尝试寻找其分层设计的最大公约数。如果把可视化搭建底层设定为逻辑层,即这个层是 UI 无关的,仅关心组件树结构、逻辑功能,那么对于每种平台的分层应该是这样的: | ||
|
||
1. 表单搭建:逻辑层、表单联动协议层、表单控件、业务层。 | ||
2. 中后台应用搭建:逻辑层、应用联动协议层、应用控件、业务层。 | ||
3. BI 仪表盘:逻辑层、筛选联动协议层、可视化控件、业务层。 | ||
4. 大屏搭建:逻辑层、画布编辑控制器层、可视化控件和基础图形控件、业务层。 | ||
|
||
最底层的逻辑层应该可以统一所有类型搭建系统,并成为开发人员统一上下文的。它可以包含以下基础能力: | ||
|
||
1. 定义组件树结构。 | ||
2. 定义组件元信息。 | ||
3. 按照组件树结构递归渲染画布。 | ||
4. 支持布局、取数、联动、筛选、校验等一系列拓展能力,业务可根据需要定制。 | ||
5. 提供所有业务层都需要的能力,比如性能优化的组件冻结、状态管理、对组件树增删改查的 API。 | ||
|
||
在逻辑层完备后,再开发上层应用就会轻松很多,只要注册组件、根据业务需要在组件树初始化或组件初始化,或组件元信息注册时添加定制逻辑,与系统功能对接,并补充业务特色的如自定义布局能力,这样就可以用简单的三言两语说清楚整个系统是如何设计的。 | ||
|
||
### 逻辑层存在的必要性 | ||
|
||
再回到问题的根源:对逻辑层做统一的抽象到底是不是多余的? | ||
|
||
要回答这个问题,需要先了解我们手头里有哪些工具:基础开发工具 html、js、css,并且 html 也提供了一套标准化的 xml 结构;vue、react 等开发框架,基础组件、应用生命周期与事件定义。理论上基于这些,我们就可以直接上手写一个可视化搭建平台了,似乎也可以不抽象。但真正要上手时,一定会遇到以下几个通用问题需要处理: | ||
|
||
**定义组件树结构** | ||
|
||
无论做表单搭建、报表搭建、大屏搭建还是脑图画布,第一个想到的肯定是如何描述这个画布结构,而无论画布是横着排还是竖着排,横竖都是一棵树。HTML 树不能直接搬过来,一是 HTML 树的完整结构太大而我们需要的更精简的结构,二是业务层框架一般都先有一套虚拟树再转化为 dom 树,因果关系也没法反过来。而这棵树也完全可以做最大程度的抽象,即定义组件 ID、组件名、属性(Props)、子节点。 | ||
|
||
**定义对组件树增删改查函数** | ||
|
||
有了组件树肯定需要对其进行增删改查操作,因为无法基于 document API,上层框架如 vue、react 也不提供对任何标准组件树的增删改查 API,这部分能力势必要手动实现。 | ||
|
||
**生命周期** | ||
|
||
假设完全依赖 React 框架提供的组件生命周期,是可以完成大部分业务逻辑,但这意味着定义不够精细化。比方说,我们在组件 Mount 的实际监听了联动、实现取数、设置冻结等等效果,虽然也可以实现,但会遇到要不要抽象的问题: | ||
|
||
- 如果不抽象,业务代码就会乱糟糟的,比较难读。 | ||
- 如果抽象,就要把联动、取数、冻结等等模块归类,封装成函数,甚至可以提供主动调用机制,UI 与逻辑解耦,但当业务层精细的去做这件事就会发现,这就是在做框架层的抽象工作,所以还不如一开始就把这些生命周期抽象到框架里。 | ||
|
||
逻辑层有两个核心结构,第一个是组件树结构,包含了对每个组件实例的定义;第二个是组件元信息结构,包含了对每个组件的元信息描述,大概如下图所示: | ||
|
||
<img width=400 src="https://user-images.githubusercontent.com/7970947/211183628-75469a31-54cf-446a-9df8-a18bb41508db.png"> | ||
|
||
逻辑层的难点就是在元信息定义足够多、足够通用的生命周期回调函数,并且这些回调函数还能尽可能的功能正交。 | ||
|
||
**组件渲染** | ||
|
||
通常一棵树按照 json 结构描述自顶向下自动渲染就可以了,但也有一些时候,比如内嵌一个富文本组件,而富文本内又嵌入一些画布组件,这些组件需要像普通画布组件一样可交互,此时就有 **渲染一个不存在于组件树的组件实例** 的需求,而这样的动态组件又要无感知的满足上面所说的各类生命周期,这也是不小的工作量。 | ||
|
||
**功能的拓展抽象** | ||
|
||
等可视化搭建平台正式维护时,就至少会遇到组件版本升级、不同类型的布局方案对接、三方组件注册等需求,这些功能如何加入到现有的搭建平台,而不让其他功能感知,是需要精心设计的。如果逻辑层把这一点抽象好,在每个功能设计一个钩子,实现一个功能时无需感知其他功能,那平台的功能拓展就会保持一个恒定的速度,不随功能增加而变得难以维护。 | ||
|
||
可见,可视化搭建不断迭代的过程就是自身不断抽象的过程,逻辑层实现的好坏直接影响到后期的维护性与拓展性,所以好好设计逻辑层可以让开发事半功倍。 | ||
|
||
### 组件配置表单要不要用搭建方案做 | ||
|
||
组件配置直接用表单方案而不是搭建,似乎是最容易想到的。但当每个组件都要自定义配置,我们就不得不选择基于 JsonSchema 描述的表单方案,但这与搭建应用本身的技术栈割裂了,随着联动功能的要求越来越多,会越来越发现小小的表单渲染引擎维护得越来越复杂,甚至复杂度与画布不分上下,此时再叹息两边技术栈不统一就已经晚了。 | ||
|
||
换个角度想一下,搭建应用不也要考虑组件间联动吗?从表单值能力来看,搭建场景并不要求每个组件都拥有一个值,反倒是可以将组件任意 props 属性看作表单值更具有 “弹性”,我们可以拓展任意 Key 作为表单值。 | ||
|
||
另外,从数据结构触发来描述表单看似很美好,但当表单变得越来越复杂,UI 越来越定制后,势必引入新的 UI 节点或者新的结构描述,与其后期拓展到一个不纯净的 JsonSchema 结构,不如一开始就放弃这个幻想,用 UI 组件树结构描述表单,这样事情就变得简单了:“先描述组件树,再定义每个节点分别用什么组件渲染,响应表单的哪部分 Key”。 | ||
|
||
## 总结 | ||
|
||
总结一下,回到主题,抽象可视化搭建的方法是分层:以逻辑层打底,提供一套标准规范与 API 接口,上层注册组件、实现布局,一切围绕着标准化的逻辑层进行拓展。 | ||
|
||
而可视化搭建的每一层都可以分别写单元测试,保证最终变化的代码只有业务层的对接部分,应用的稳定性就提高了。 | ||
|
||
最后提一个思考题:你是觉得可视化搭建应该如何抽象?如果想要做到每一层独立正交,你会如何设计 API 呢? | ||
|
||
> 讨论地址是:[精读《如何抽象可视化搭建》· Issue #463 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/463) | ||
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。** | ||
|
||
> 关注 **前端精读微信公众号** | ||
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg"> | ||
|
||
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)) |