从0开始搭建低代码平台系列(难点分析)


这是如何搭建低代码系列的第二篇文章,最近快放假了,所以也不是很忙,所以才能在这段时间连续发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的阶段了,有兴趣的童鞋可以找到我的第一篇博客然后找到对应的代码研究下~。

  • 分享:
评论
还没有评论
    发表评论 说点什么