Angular动态表单生成(二)

ng-dynamic-forms源码分析

在两个开源项目中,ng-dynamic-forms的源码相较于form.io,比较简单,所以我还勉强能看懂,下面就我自己的理解进行简单分析,若有不对的地方,请大家多多指正。

整体结构分析

ng-dynamic-forms的主要代码均分布在packages文件夹下,其中的Core是各种控件的抽象,其他的文件夹是各个UI框架的具体封装,每个文件夹都是一个可独立编译运行的项目。

image

Core文件夹内容分析

Core文件夹做的事情,基本上是对于各种组件、布局的抽象,说简单点,就是定义了,这个框架有哪些组件,这些组件都有哪些事件、哪些方法。接下来我们具体分析一下:

utils文件夹:

这个文件夹最不重要,是一些工具类的封装,无需多解释

component/dynamic-form-component文件:

这个文件定义了表单(<form></form>)的抽象类DynamicFormComponent,也就是一组表单控件的集合,将来每种UI库的都会有该类的子类,并根据需要重写其中的一些方法和属性。

它实现了一些基础的事件和属性。

事件:blur,change,focus,customerEvent

属性:formGroup、formModel、formLayout

component/dynamic-form-control.component文件:

这个文件定义了表单的表单元素的抽象类DynamicFormControlComponent,将来每个UI控件的具体类,都要继承自该类,并更新需要进行重写和扩展。

该类具有以下事件和属性:

事件:onControlValueChanges,onModelValueUpdates,onModelDisabledUpdates,onValueChange,onBlur,onFocus,onCustomEvent

属性:errorMessages,showHint,hasList,isInvalid,isValid,showErrorMessages,templateList

decorator/serializable.decorator文件:

定义了一个公共的装饰器,用于方便传入Key-Value形式的属性。

model文件夹:

model文件夹是整个Core文件夹中,比较重要的一块,他定义了动态表单所支持的表单元素的和一些表单包裹元素。

总体来说,ng-dynamic-forms将控件分为如下几类:

输入类:文本框,文本域,富文本编辑框

单值类:包含所有的输入类、选择类控件,另外还有颜色选择器、日期选择、文件选择组件、评分组件、滑动组件

选择类:复选框(CheckBox)、开关(Switch)

选项类:下拉框、单选框

日期类:日期选择组件、时间选择组件

文件类:文件上传组件

布局类:FormGroup、FormArrary

Service文件夹:

dynamic-form.service:

主要一些对FromGroup、FromArrary中表单元素动态增删改的操作,以及通过Json数据创建表单的操作

dynamic-form-layout.service:

表单布局的一些相关方法,方便表单元素找到他外层包裹的容器的样式、ID类的

dynamic-form-validation.service:

从名字就可以看出来,这个服务是用来做表单校验的

UI库实现分析

前面赘述了一堆,都是ng-dynamic-forms的抽象实现,那具体到每一种UI组件是如何套用的呢?让我们一起来看看吧~

我们以ui-bootstrap的实现为例:

文件夹结构

image

基本上每个UI库的大概结构都如上图所示,其中:

dynamic-bootstrap-form.component 中的DynamicBootstrapFormComponent类,是继承自Core中的 DynamicFormComponent,它的HTML模板中的代码如下:

<dynamic-bootstrap-form-control *ngFor="let model of formModel; trackBy: trackByFn"
                                [group]="formGroup"
                                [hasErrorMessaging]="model.hasErrorMessages"
                                [hidden]="model.hidden"
                                [layout]="formLayout"
                                [model]="model"
                                [ngClass]="[getClass(model,'element','host'), getClass(model,'grid','host')]"
                                [templates]="templates"
                                (dfBlur)="onEvent($event, 'blur')"
                                (dfChange)="onEvent($event, 'change')"
                                (dfFocus)="onEvent($event, 'focus')"></dynamic-bootstrap-form-control>

首先他有ngFor来循环各种表单控件,然后定义了一个FromGroup来包装这些组件,并且绑定了各种事件、样式等等,看到这里,应该稍微明白点了,这个东东,他是用来生成各种控件外面包裹的部分的。

接着往下看,文件夹中还会有一个dynamic-bootstrap-form-control.component文件,打开ts文件,里面貌似没有啥东西,然后再打开html文件,就会发现另一番天地了,里面N多的类似于下面的代码:

<!-- SELECT -->
            <select *ngSwitchCase="7" class="form-control"
                    [dynamicId]="bindId && model.id"
                    [formControlName]="model.id"
                    [name]="model.name"
                    [ngClass]="getClass('element', 'control')"
                    [required]="model.required"
                    [tabindex]="model.tabIndex"
                    (blur)="onBlur($event)"
                    (change)="onValueChange($event)"
                    (focus)="onFocus($event)">

                <option *ngFor="let option of model.options$ | async"
                        [disabled]="option.disabled"
                        [ngValue]="option.value">{{ option.label }}</option>

            </select>

从这个代码,我们可以分析出,这个部分,他是根据不同的type,来生成不同的控件的html,并且bootstrap的控件样式也是直接定义到这个文件中的。

总结

前面乱七八糟分析的一大堆,可能说的比较乱,我们来整体屡一下整体的思路:

首先,由Core中定义了控件的公共行为和属性,是所有控件库的一套抽象,主要包括三部分:

  1. 一部分是控件的布局用到的,即包裹表单控件的外层容器
  2. 另一部分是基础的控件,包括整个框架支持哪些控件,这些控件有拥有哪些属性,这些属性往往是不同UI库中该控件共同所有的部分
  3. 还有一部分是定义了表单控件的校验部分

其次,该项目中实现众多市面上常见的UI库,这部分主要干了两个事儿:

  1. 通过实现Core中定义的抽象,将各种属性和UI库中的控件中对应的属性绑定起来
  2. 另一方面,将最终使用时动态的控件定义,按照UI库的样式、结构生成HTML

就是通过这样一种模式,该框架将一个个控件的对象,最终转换成UI中展示的HTML。

原文地址:https://www.cnblogs.com/baiyunchen/p/8469665.html