这是如何搭建低代码系列的第二篇文章,最近快放假了,所以也不是很忙,所以才能在这段时间连续发2篇,第二篇依旧是比较偏向设计的,也许有人觉得麻烦,其实不是,一个系统只有具备了良好的设计才能具有发展潜力。
关于antd渲染结果的分析
因为本次低代码是基于antd框架去做的,所有渲染出来的结果的风格和antd类似。为了更加精准的渲染出, 我们想要的效果,所以分析antd是必不可少来的。废话不多说,上图。
以一个最基本的筛选框为例子,我们可以发现整体渲染可以分为3层。
第一层,第二层ant-form-item-control-input,ant-form-item-control-input-contet,这是我采用的antd的form组件的渲染结果,每一个都会包一层这个,我们在做ui渲染的时候可以默认渲染上去,所有的渲染默认都是这个样子的,所以我们可以通过一个统一的入口去加上,比如我这里就是直接上了一个DOMUtils,自己去包装的外壳(当然应该还是有其他方案可以探索的)。
第三层开始也就是我们组件需要去渲染的一层了,从这层开始就需要第一篇文章中所提到的,最初设计的数据结构了。下面的代码是实现过程中的一个简单的描述,通过这样的方式把每一层的结构都描述出来。(懂行的大哥可能会发现这和虚拟dom有点类似,确实我的设想就是描绘一个类似的数据结构,然后我们去解析生成。
也许也有人会有疑问,生成这么一个结构是否会耗费性能,其实确实会耗费性能,但是我们的树深度是有限的,最多的不过是4层,所产生的消耗微乎其微。
dom数据结构
/**
* DOM数据结构
*/
export interface RenderDOM {
domType: string;
type: string;
class?: string;
value?: string;
placeholder?: string;
isDisabled?: boolean;
size?: {
rows?: number,
cols?: number
}; // 显示行数,多行文本框需要
children?: RenderDOM[]; // 可能存在多层级嵌套(当然也可能是存在多个孩子节点)
}
组件数据结构实例
{
key: 'radio',
name: '单选按钮组',
type: 'radio',
icon: 'icon-danxuananniuzu',
dom: {
domType: 'div',
type: 'div',
class: 'ant-radio-group ant-radio-group-outline',
children: [
{
domType: 'label',
type: 'label',
class: 'ant-radio-wrapper',
children: [
{
domType: 'span',
type: 'span',
class: 'ant-radio',
children: [
{
domType: 'input',
type: 'radio',
class: 'ant-radio-input',
value: '',
},
{
domType: 'span',
type: 'span',
class: 'ant-radio-inner',
}
]
},
{
domType: 'span',
type: 'span',
value: '',
}
]
}
]
}
},
说了这么多,上面看代码或许有点抽象,其实它就是一棵树,一颗多叉树。
上图就是对一个组件渲染的描述,这么看就简单了很多。我们需要做的就是采用某种算法渲染出上诉的div即可,这里我选择了dfs,深度优先整好满足了我的需求。
渲染路径如下:
第一轮:div – div – span – input
第二轮: – span
经过2轮即可完成dom树的渲染。
如何存储UI数据
这里确实是个难点,因为数据的存储效果决定了,这个系统的可扩展性,数据结构强大,那么程序的可扩展性也就很强。
这点我暂时准备独立产生一个UIStoreService对所有的存储提供服务。
针对这些特色,我们的数据结构设计如下(暂时~这么设计,后续还会根据不同进行扩展)。
export interface Line {
componentNums: number; // 组件数量
lineStyle: string; // 行样式
component: {
slider: number; // 组件所站一行的栅栏
componentType: string; // 组件类型
componentName: string; // 组件名称
styles: string; // 组件样式
isNeed: boolean; // 是否必填
reg?: string; // 正则表达式
}[];
}
所有的数据都是按行存储,这样大大降低了解析难度,同时为了保证一次就能生成可用的文件,我们在加入antd组件的时候,会自动将需要import的组件也设计的渲染模版。这是生成文件的时候会调用~
import `{${
components // 遍历
}}` from antd
数据存储完了,我们下一步就是对拿到的数据进行解析了。
这里就呼应了上面提到的UIStoreService这个就是对ui数据进行解析,最后渲染成可运行代码的地方。
如何精确渲染
因为我们做的低代码平台,其实对于ui的精确渲染还是有一定的必要的。所以我在第一篇文章中提到了,render分包这么一个概念,这也是做渲染的一种策略,
因为低代码涉及到的组件比较多,如果按需渲染,精确渲染就成了这类开发着不得不思考的问题,我这里的话计划分组件render,我们将组件分成了3大类。
1.按钮型
2.输入型
3.选择型
分类依据就是根据dom层级来区分。按钮型普遍都只具有1层dom,输入型有1到2层,选择型为3层-4层。
经过这么一个操作,我们所绘制的组件就被完美呈现在了浏览器上了。
结尾
今天的文章比较随意,没有按照章法来,就想分享一下我关于设计这块的思路。其实代码的话,我已经实现到了绘制UI的阶段了,有兴趣的童鞋可以找到我的第一篇博客然后找到对应的代码研究下~。