- 文档
- 技术博客
- 教程
【免费下载链接】weekly
前端精读周刊。帮你理解最前沿、实用的技术。
导读:本文是"前端精读周刊"可视化搭建系列的开篇之作,聚焦"做任何可视化搭建项目前必须先思考的抽象问题"。文章以表单搭建、中后台搭建、BI 仪表盘、大屏搭建四类场景为样本,论证它们背后存在一个 UI 无关的"逻辑层"最大公约数,并逐条拆解逻辑层必须解决的组件树结构、增删改查、生命周期、渲染与拓展五大问题。读完本文,你将掌握一套"以逻辑层打底、上层注册组件与布局"的分层抽象方法论,为后续亲手实现一个 React 可视化搭建器(组件树 + 组件元信息 + 数据流铁三角)打下理论基础。
为什么做可视化搭建,第一步必须先思考"抽象"
在做任何可视化搭建项目时,第一步都要思考如何抽象。这不是一句口号,而是有明确后果的:
- API 杂乱、难以维护:如果不抽象,搭建项目做到后期,API 会越堆越多且彼此纠缠,代码熵增导致维护成本飙升。
- 自我怀疑:做到一半甚至会怀疑"为什么需要一个搭建框架",怀疑把框架去掉会不会效率更高。
- 无法水平拓展:后期会发现系统不能自然地水平拓展到仪表盘、大屏、表单搭建等新场景,每次新场景都要重新造轮子。
所以,无论维护的可视化搭建系统上层是 BI、大屏、表单填报还是脑图,都要先思考:这些系统背后的底层是什么?需不需要抽象?抽象的意义和价值在哪里?
以本仓库系列后续篇章为例,抽象的价值在 可视化搭建/269.组件注册与画布渲染.md 中体现为极简的<Designer>API(componentMetas+componentTree两个入参即可渲染画布),在 可视化搭建/270.画布与组件元信息数据流.md 中体现为"数据流、组件元信息、组件实例三者的铁三角",这正是前期抽象沉淀下来的成果。
什么是可视化搭建:边界与归类
表单搭建、中后台应用搭建、BI 仪表盘搭建、大屏搭建都算可视化搭建,因为它们都是在一个画布上拖拖拽拽完成的。
那么边缘场景如何归类?
- 组件配置表单:如果基于 UI 组件树抽象,它就是可视化搭建;如果基于表单结构抽象,它就是 JsonSchema。
- 聚焦单组件分析的可视化探索、幻灯片:同样存在归类问题。
关键判断在于:所有业务场景都是"数据完全映射 UI"吗?不一定。UI 可以为了用户操作方便加入更多辅助元素,甚至把一个属性拆成多个 UI 填写。所以基于 UI 组件树抽象的可视化搭建,一定可以覆盖所有表单场景,但不一定是描述效率最高的方式。
如果不做统一抽象,后果是:
- 每种可视化搭建场景各定义一套协议与实现,按平台复杂度算,同时维护两套类搭建平台的成本是两倍;
- 不同维护人员之间很难交流;
- 有些本可按搭建思路解决的场景,因实现时经验不足没有抽象,甚至另做了一套定制抽象,回过头来积重难返,团队不得不接受多套笨重实现并存的现状。
因此建议:将这些场景都视为可视化搭建场景,用一套接口描述结构、API 方法,让看似百花齐放的编辑器之下拥有统一的上下文与实现。
可视化搭建的分层:寻找四类平台的最大公约数
对于不同种类的可视化搭建平台,可以尝试寻找其分层设计的最大公约数。把可视化搭建底层设定为逻辑层——即这一层是 UI 无关的,仅关心组件树结构、逻辑功能——那么四类典型平台的分层结构如下:
| 平台类型 | 分层结构 |
|---|---|
| 表单搭建 | 逻辑层、表单联动协议层、表单控件、业务层 |
| 中后台应用搭建 | 逻辑层、应用联动协议层、应用控件、业务层 |
| BI 仪表盘 | 逻辑层、筛选联动协议层、可视化控件、业务层 |
| 大屏搭建 | 逻辑层、画布编辑控制器层、可视化控件和基础图形控件、业务层 |
可以看到,逻辑层位于所有类型搭建系统的最底层,是开发人员统一上下文的关键。逻辑层应包含以下基础能力:
- 定义组件树结构。
- 定义组件元信息。
- 按照组件树结构递归渲染画布。
- 支持布局、取数、联动、筛选、校验等一系列拓展能力,业务可根据需要定制。
- 提供所有业务层都需要的能力,比如性能优化的组件冻结、状态管理、对组件树增删改查的 API。
逻辑层完备后,开发上层应用会轻松很多:只要注册组件、根据业务需要在组件树初始化、组件初始化或组件元信息注册时添加定制逻辑、与系统功能对接,并补充业务特色的自定义布局能力,就可以用简单的三言两语说清楚整个系统是如何设计的。
佐证:本仓库系列中,可视化搭建/271.可视化搭建内置 API.md 正是逻辑层"能力 5"的具体展开——围绕组件树核心概念设计了
addComponent、deleteComponent、setProps、undo/redo等 API,且全部以组件 ID 为参数、内部转为组件树操作,并内置 O(1) 时间复杂度的映射优化。而 可视化搭建/279.自动批处理与冻结.md 中"冻结"能力,则与"能力 5"中性能优化诉求一一对应。
逻辑层存在的必要性:五个绕不开的通用问题
回到问题根源:对逻辑层做统一抽象,到底是不是多余的?
我们手头的工具其实很充分:基础开发工具 html、js、css(html 还提供了标准化的 xml 结构);vue、react 等开发框架、基础组件、应用生命周期与事件定义。理论上基于这些就可以直接上手写一个可视化搭建平台,似乎可以不抽象。但真正动手时,一定会遇到以下五个通用问题。
1. 定义组件树结构
无论做表单搭建、报表搭建、大屏搭建还是脑图画布,第一个想到的问题一定是:如何描述画布结构?而无论画布横排还是竖排,横竖都是一棵树。
但HTML 树不能直接搬过来,原因有二:
- HTML 树的完整结构太大,而我们需要的结构更精简;
- 业务层框架一般先有一套虚拟树再转化为 dom 树,因果关系没法反过来。
这棵树可以做到最大程度的抽象,即只定义:组件 ID、组件名、属性(Props)、子节点。本系列后续在 可视化搭建/269.组件注册与画布渲染.md 中落地为ComponentInstance结构:
{ "componentName": "container", "children": [ { "componentName": "text", "props": { "name": "我是一个文本组件" } } ] }三个核心要素缺一不可:componentName描述组件类型(没有它无从渲染);props承载该实例的全部配置(透传给组件);children描述子组件(建议同时支持children与props.children两种位置,同时定义时前者优先级更高)。可选属性componentId用于组件移动后保持唯一性,因为组件树路径(如children.0)是天然 ID,但移动后会失效。
2. 定义对组件树增删改查函数
有了组件树,肯定需要对其进行增删改查操作。因为无法基于 document API,上层框架如 vue、react 也不提供对任何标准组件树的增删改查 API,这部分能力势必要手动实现。
本系列在 可视化搭建/271.可视化搭建内置 API.md 中给出了完整答案:以setComponentTree()为底层基石,派生出addComponent()、deleteComponent()、getComponent()、setComponent()、setProps()等便捷 API。核心 API 只有寥寥几个,其余 API 都以便利性为目的、以核心 API 为基础实现,这样框架核心更稳定。
3. 生命周期
假设完全依赖 React 框架提供的组件生命周期,可以完成大部分业务逻辑,但这意味着定义不够精细化。比如在组件 Mount 时实际监听联动、实现取数、设置冻结等效果,虽然也能实现,但会遇到"要不要抽象"的问题:
- 如果不抽象:业务代码乱糟糟的,比较难读。
- 如果抽象:就要把联动、取数、冻结等模块归类封装成函数,甚至可以提供主动调用机制,让 UI 与逻辑解耦。但业务层精细地去做这件事时就会发现——这就是在做框架层的抽象工作,所以还不如一开始就把这些生命周期抽象到框架里。
逻辑层有两个核心结构:组件树结构(对每个组件实例的定义)与组件元信息结构(对每个组件的元信息描述)。逻辑层的难点在于:元信息定义足够多、足够通用的生命周期回调函数,且这些回调函数还能尽可能功能正交。
佐证:本系列把"生命周期"落到了组件元信息的各个回调钩子上——可视化搭建/273.组件值与联动.md 的
valueRelates、可视化搭建/274.定义联动协议.md 的runtimeProps、可视化搭建/275.组件值校验.md 的valueValidator、可视化搭建/279.自动批处理与冻结.md 的fetcher/init等。它们彼此正交、互不感知,正是"功能正交"设计目标的具体体现。
4. 组件渲染
通常一棵树按 json 结构自顶向下自动渲染即可,但存在特殊场景:比如内嵌一个富文本组件,而富文本内又嵌入一些画布组件,这些组件需要像普通画布组件一样可交互。此时就有了"渲染一个不存在于组件树的组件实例"的需求,而这样的动态组件又要无感知地满足上述各类生命周期,这也是不小的工作量。
佐证:该问题在 可视化搭建/278.ComponentLoader 与动态组件.md 中得到解决——
<ComponentLoader>支持按组件 ID 加载(componentId)、按组件树路径加载(treePath,如children.0)以及standalone动态组件三种用法,且<Canvas />根节点本质上等价于<ComponentLoader treePath="" />。
5. 功能的拓展抽象
等可视化搭建平台正式维护时,至少会遇到三类需求:组件版本升级、不同类型的布局方案对接、三方组件注册。这些功能如何加入到现有平台而不让其他功能感知,需要精心设计。如果逻辑层把这一点抽象好——在每个功能设计一个钩子,实现一个功能时无需感知其他功能——平台的功能拓展就会保持恒定速度,不随功能增加而变得难以维护。
佐证:本系列在 可视化搭建/270.画布与组件元信息数据流.md 中提供了统一的数据流拓展入口:通过
createDesigner()创建上下文隔离的Designer/Canvas/useDesigner,业务可自由注册actions与state(受控模式),或用createMiddleware自定义中间件(非受控模式)。所有定义的状态与方法,无论在内置函数还是组件元信息回调中都能统一访问,这正是"功能拓展不感知其他功能"的落地。
可见,可视化搭建不断迭代的过程,就是自身不断抽象的过程。逻辑层实现的好坏直接影响到后期的维护性与拓展性,所以好好设计逻辑层可以让开发事半功倍。
组件配置表单:要不要用搭建方案做
组件配置直接用表单方案而不是搭建,似乎是最容易想到的。但当每个组件都要自定义配置,我们就不得不选择基于 JsonSchema 描述的表单方案,而这与搭建应用本身的技术栈割裂了。随着联动功能要求越来越多,会越来越发现小小的表单渲染引擎维护得越来越复杂,甚至复杂度与画布不分上下,此时再叹息两边技术栈不统一就已经晚了。
换个角度想:搭建应用不也要考虑组件间联动吗?从表单值能力来看,搭建场景并不要求每个组件都拥有一个值,反倒是可以将组件任意 props 属性看作表单值,这样更具有"弹性"——我们可以拓展任意 Key 作为表单值。
另外,从数据结构出发描述表单看似很美好,但当表单变得越来越复杂、UI 越来越定制后,势必引入新的 UI 节点或新的结构描述。与其后期拓展到一个不纯净的 JsonSchema 结构,不如一开始就放弃这个幻想,用 UI 组件树结构描述表单。这样事情就变得简单了:"先描述组件树,再定义每个节点分别用什么组件渲染,响应表单的哪部分 Key"。
佐证:本系列在 可视化搭建/270.画布与组件元信息数据流.md 中确实做到了"用一套技术方案同时实现画布与配置表单"——通过
createDesigner创建一套上下文独立的 API,画布、配置面板都可以用 Designer 实现,学习上下文与组件规范统一为一套,表单与画布能力共享。
总结
回到主题,抽象可视化搭建的方法是分层:以逻辑层打底,提供一套标准规范与 API 接口;上层注册组件、实现布局,一切围绕着标准化的逻辑层进行拓展。
两条实践建议值得铭记:
- 分层 + 单测:可视化搭建的每一层都可以分别写单元测试,保证最终变化的代码只有业务层的对接部分,应用的稳定性随之提高。
- 正交的 API 设计:如果一个功能被设计为钩子,实现时无需感知其他功能,那么无论后续叠加组件版本升级、布局方案对接还是三方组件注册,平台的拓展速度都能保持恒定。
最后留一个思考题:你觉得可视化搭建应该如何抽象?如果想要做到每一层独立正交,你会如何设计 API?带着这个问题去研读本仓库可视化搭建系列接下来的篇章(组件注册与画布渲染、画布与组件元信息数据流、可视化搭建内置 API、组件值与联动、定义联动协议、组件值校验、keepAlive 模式、ComponentLoader 与动态组件、自动批处理与冻结),你会看到一套完整的"抽象落地"路径——从本文的"逻辑层"理论,到 可视化搭建/269.组件注册与画布渲染.md 的组件树与组件元信息两个核心概念,再到 可视化搭建/270.画布与组件元信息数据流.md 中"数据流、组件元信息、组件实例"的铁三角设定,直至 可视化搭建/280.场景实战.md 的综合演练。
- 文档
- 技术博客
- 教程
【免费下载链接】weekly
前端精读周刊。帮你理解最前沿、实用的技术。
相关推荐
30 分钟搭好一个 ESP32 温湿度光照监测节点,硬件不到 150 元
30 分钟搭好一个 ESP32 温湿度光照监测节点,硬件不到 150 元 昨晚回家,卧室又闷又干,空调到底有没有在制热、绿植盆土干了没有,全靠感觉。这类"人不在
嵌入式物联网驱动开发Higress 插件生态指南:7 个热门社区扩展快速上手
Higress 插件生态指南:7 个热门社区扩展快速上手 本文基于开源项目 Higress(AI Native API Gateway),面向新手推荐并讲解 7
API网关后端云原生LLM 网关人工智能MCP 服务深入解析Video2X:基于机器学习的视频超分辨率与帧插值框架终极指南
深入解析Video2X:基于机器学习的视频超分辨率与帧插值框架终极指南 Video2X是一个基于机器学习的高性能视频超分辨率和帧插值框架,能够将低分辨率视频无损
音视频视频处理图像处理深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考