当前位置: 首页 > Web前端 > JavaScript

精读《如何抽象可视化搭建》

时间:2023-03-27 02:01:31 JavaScript

在做任何视觉构建项目时,第一步都是思考如何抽象。如果不抽象,后期构建项目时,API可能会比较乱,难以维护;进行到一半,你甚至会疑惑为什么需要搭建框架,去掉框架会不会更高效;后期发现不自然横向扩展到仪表盘、大屏,形成搭建场景。所以如果你在维护一个可视化构建系统,不管系统上层是BI、大屏、填表、还是脑图,不管是什么,你首先要思考这些背后的底层是什么系统。需要抽象,抽象的意义和价值在哪里。下面结合笔者的经验尝试给出一个思考的角度。精读什么是可视化构建表单构建、中后台应用构建、BI仪表盘构建、大屏构建都属于可视化构建,因为它们都是在画布上拖拽完成的。那么组件配置形式算不算构建呢?专注于单组分分析的视觉探索怎么样?幻灯片呢?比如组件配置表单,如果是基于UI组件树的抽象,就是可视化构建,但是如果是基于表单结构的抽象,就是JsonSchema,但是是不是所有的业务都场景完全将数据映射到UI?不一定,因为UI为了方便用户操作可以增加更多的辅助元素,甚至可以把一个属性拆分成多个UI来填充,所以是基于可视化构建的,即抽象的UI组件树当然可以覆盖所有形成场景,但不一定是最有效的描述方式。如果每个可视化构建场景都定义了一套协议和实现,那么根据构建平台的复杂程度,同时维护两类构建平台的成本要成倍增加,而且不同的维护者也很难沟通。或者一些按照构建思路可以解决的场景,因为缺乏实现经验,没有抽象,甚至是另外一套自定义抽象,回想起来可能很难回归,团队不得不接受现状多套实施繁琐的现状。所以,建议把这些场景当成可视化的构建场景,用一套接口来描述结构和API方法,让看似百花齐放的编辑器有一个统一的语境和实现。视觉构建的分层针对不同类型的视觉构建平台,我们试图找到其分层设计的最大公约数。如果将可视化构建的底层设置为逻辑层,即这一层与UI无关,只关心组件树结构和逻辑功能,那么对于各个平台的分层应该是这样的:表单构建:逻辑层、窗体联动协议层、窗体控制、业务层。中后台应用构建:逻辑层、应用联动协议层、应用控制、业务层。BI仪表盘:逻辑层、筛选联动协议层、可视化控制、业务层。大屏构建:逻辑层、画布编辑控制器层、可视化控制和基本图形控制、业务层。最低的逻辑层应该能够统一所有类型的构建系统,成为开发者的统一上下文。它可以包括以下基本功能:定义组件树结构。定义组件元信息。根据组件树结构递归渲染画布。支持布局、取数据、联动、筛选、验证等一系列扩展能力,业务可按需定制。提供所有业务层所需的能力,如性能优化的组件冻结、状态管理、组件树增删改查API等。逻辑层完成后,开发上层应用程序就会容易很多。只需注册组件,在初始化组件树或组件初始化时添加自定义逻辑,或根据业务需要注册组件元信息,对接系统功能,补充业务特性。比如自定义布局的能力,这样你就可以用简单的话来解释整个系统是如何设计的。逻辑层存在的必要性又回到了问题的根源:对逻辑层进行统一抽象是否多余?要回答这个问题,我们需要知道我们有哪些工具:基本的开发工具html、js、css,而html也提供了一套标准化的xml结构;vue、react等开发框架、基础组件、应用生命周期、事件定义。理论上,基于这些,我们可以直接手写一个可视化构建平台,而且好像不需要抽象。但是当你真正要上手时,肯定会遇到以下一般需要处理的问题:定义组件树结构无论你是构建表单、报表、大屏幕还是脑图画布,首先想到的肯定是canvas的结构怎么描述,不管canvas是横排还是竖排,反正都是一棵树。不能直接移动HTML树。首先,HTML树的完整结构太大,我们需要一个更精简的结构。第二,业务层框架一般先有一组虚拟树,然后再转化为dom树,因果关系不可逆。.而这棵树也可以最大程度的抽象,即定义组件ID、组件名称、属性(Props)、子节点。定义组件树的增删改查功能。有了组件树,需要进行增删改查操作,因为不能基于文档API,而vue、react等上层框架没有提供增删改查的API检查任何标准组件树。这部分Capabilities必然要手动实现。生命周期假设完全依赖React框架提供的组件生命周期,可以完成大部分业务逻辑,但这意味着定义不够细化。比如在组件Mount的实际监控中,我们监控了联动、取数据、设置冻结等效果,虽然也可以实现,但是会遇到是否抽象的问题:如果不是抽象了,业务代码就乱了。难读。如果是抽象的,需要将联动、取数据、冻结等模块进行分类,封装成函数,甚至提供主动调用机制,将UI与逻辑解耦,但是当业务层具体做到这一点时,你会发现,这是在做框架层的抽象工作,所以一开始就把这些生命周期抽象到框架中比较好。逻辑层有两个核心结构。首先是组件树结构,其中包含了每个组件实例的定义;二是组件元信息结构,包含了各个组件的元信息描述,如下图所示。显示:逻辑层的难点在于定义足够的元数据,足够通用的生命周期回调函数,并且这些回调函数也可以在功能上尽可能正交。组件渲染通常是一棵树根据json结构描述从上到下自动渲染就够了,但是有时候,比如嵌入一个富文本组件,在富文本中嵌入一些canvas组件,而这些组件需要像普通的canvas组件一样,也可以交互。这时候就需要渲染一个组件树中不存在的组件实例,而这样一个动态的组件需要在无感知的情况下满足上面提到的各种生命周期,这是一个不小的工作量。功能扩展、抽象等可视化构建平台在正式维护时,至少会遇到组件版本升级、不同类型布局方案对接、三方组件注册等需求。如何在不让其他功能感知的情况下,将这些功能添加到现有的构建平台中,需要精心设计。如果逻辑层很好地抽象了这一点,为每个功能都设计了一个hook,在实现一个功能的时候不需要去感知其他功能,那么平台的功能扩展就会保持一个恒定的速度,不会变得难以维护随着功能的增加。可见,可视化构建的不断迭代过程是一个不断抽象的过程。逻辑层实现的好坏直接影响到后期的可维护性和可扩展性。因此,设计良好的逻辑层可以使开发更加有效。组件配置表单似乎最容易想到要不要用构造方案来做组件配置,直接用表单方案代替构造。但是当每个组件都需要自定义配置时,我们不得不选择基于JsonSchema描述的表单解决方案,但这与构建应用本身的技术栈是分离的。随着联动功能需求越来越多,会发现小表单渲染引擎的维护越来越复杂,甚至复杂程度堪比canvas。这个时候再感叹双方的技术栈不统一也来不及了。换个角度想想,你在构建应用的时候不也需要考虑组件之间的联动吗?从表单赋值能力来看,构建场景并不需要每个组件都赋值。相反,将组件的任意一个props属性作为一个表单值来处理会更加“灵活”,我们可以将任意一个Key扩展为一个表单值。另外,由数据结构触发的表单描述看起来很美,但是当表单越来越复杂,UI越来越定制化的时候,势必会引入新的UI节点或者新的结构描述,而不是扩展对于一个不纯的JsonSchema结构,一开始最好放弃这种幻想,使用UI组件树结构来描述表单,这样事情就变得简单了:“先描述组件树,再定义使用哪些组件渲染每个节点,以及表单的哪一部分响应Key”。综上所述,回归正题,抽象可视化构建的方法是分层的:以逻辑层为基础,提供一套标准规范和API接口,在上层注册组件,实现布局,围绕标准化逻辑进行扩展层。可以为可视化构建的每一层单独编写单元测试,保证最终改动的代码只是业务层的对接部分,提高了应用的稳定性。最后是一个思考问题:你认为可视化构建应该抽象到什么程度?如果你想让每一层都独立和正交,你会如何设计一个API?讨论地址为:Jingdu《如何抽象可视化搭建》·Issue#463·dt-fe/weekly想参与讨论的请戳这里,每周都有新话题,周末或周一发布。前端精读——帮你过滤靠谱的内容。关注前端精读微信公众号版权声明:免费转载-非商业-非衍生保留属性(CreativeCommons3.0License)