1 表单控件简介
表单控件是针对表单模型扩展的基础插件,典型的表单控件有单对象控件,多对象控件,布局控件等,表单控件在建模工具中供用户拖放并且修改配置,这些配置在应用前端展示。
在本教程的第二部分大量表单控件的例子,有兴趣的读者通过 第三章 表单建模入门,详细了解表单控件的使用方法。本章主要介绍如何扩展现有的表单控件,通过本章的练习,读者可以开发一个最简单的控件,姑且称为入门控件,如下所示:
图-入门控件在建模工具中的表现形式
图-入门控件在应用端表单的表现形式
1.1 控件代码的位置和装配方式
和操作插件一样,表单控件对应的程序入口也是一个vue文件,DWF的表单引擎会在启动的时候动态加载这个.vue文件。
由于表单控件在建模工具和应用前端各有不同,因此需要将表单控件分成两个不同的vue文件,分别放入下面的文件夹forms中,在本章的例子中可以分别建立一个helloControl.vue文件,下面是相对路径:
- dwf-part-all\[代码包名称]\part-web\app\forms\helloControl.vue
- dwf-part-all\[代码包名称]\part-web\modeler\forms\helloControl.vue
控件对应的vue文件开发好以后,装配脚本会将vue文件拷贝到app-web或者modeler-web核心代码中的“assemble_components\form\[代码包名称]”文件夹中,并且自动更新核心代码的assemble_config.js文件,装配的配置文件所在位置如下:
- dwf-part-all\[代码包名称]\part-web\modeler\assemble-to.yaml
- dwf-part-all\[代码包名称]\part-web\app\assemble-to.yaml
通过在assemble-to.yaml中增加forms标签中的内容即可增加一个插件的装配信息,以helloControl.vue为例,在modeler文件夹对应配置如下所示:
config: ignore: info: part-web: name: modeler cname: 建模端 forms: helloControl.vue: from/single dependencies: {}
form:标签的格式是:“vue文件名:控件归属类别”,其中归属类别有:
布局:form/layout
单对象控件:form/single
多对象控件:form/multi
时间序列:form/timeseries
模型点选控件:form/model
可视化控件:form/visual
注:如果需要引用第三方依赖,可以写在assemble-to.yaml中指定,填写要求为【依赖名:^依赖版本】,这个写法和npm-package中的依赖声明方法是一致的,如:
dependencies: vue-calendar-component: ^2.8.2
调试阶段,在命令行内输入devAssemble即可实现开发阶段的自动装配,如果需要清除则输入devClear即可:
PS D:\DWF3.0> cd .\scripts\ PS D:\DWF3.0\scripts> python .\assemble.py devClear 当前处于本地开发环境,仅支持代码打包和本地前端装配、卸载 ,请确认assemble-to.yaml填写正确 devClear start devClear end PS D:\DWF3.0\scripts> python .\assemble.py devAssemble 当前处于本地开发环境,仅支持代码打包和本地前端装配、卸载 ,请确认assemble-to.yaml填写正确 devAssemble start assemble_config.js和package.json更新成功 devAssemble end
1.2 表单的控件的JSON规范
了解了代码位置和装配方法以后,接下来介绍一下表单的JSON格式,打开表单建模工具任意新建一张空白表单,点击JSON图标,可以看到表单对应的原始格式,结构如下:
图-打开表单的JSON格式
下面是对应的表单JSON格式:
{ "data": { "elements": [ { "self": { "elementType": "addin_helloControl", "properties": { "uuid": "B0D6C0532C4F42C3AE1BBA5746F49441", "id": "helloControl1" }, "dropTarget": "0", "uuid": "B0D6C0532C4F42C3AE1BBA5746F49441" }, "elements": [] } ], "targetClass": "Part", "isRelation": false, "basicArgs": { "label_width": 2, "main_width": 3, "label_align": 4, "main_align": 4, "row_space": 0, "col_space": 0, "label_fontColor": "initial", "txt_fontColor": "initial", "form_bgColor": "#fff", "form_fsize": 14, "form_font_size": "14px", "lfsize": 14, "fsize": 14, "label_align_horizontal": "1", "label_align_vertical": "1", "main_align_horizontal": "4", "defaultMultiAddin": "" }, "deviceType": "actPc" } }
其中,整个表单的内容在data属性之下,在最顶层是表单的一些基本信息,这些信息包括:
"elements":表示表单中包含的控件配置信息,每一个画布内的控件对应一个数组内的元素,元素中的self表示控件自身的属性这些属性有:
elementType表示控件的英文名,该名字有控件实现的时候实现,后续内容将介绍如何实现。
properties是控件用于绘制自身的时候需要记录的配置信息,其中
uuid是引擎内部使用的唯一代号,id是对外的代号,每当控件被实例化到画布中的时候会自动为其分配一个代号。uuid一般不会发生变化,因此,自动化测试工具可以利用这个代号找到控件。
其他配置属性则由控件的开发人员自行添加,其实现方法将在后续介绍。
除了self以外,对于布局类控件需要包含多个子控件,因此,element下面可以继续包含elements。
"targetClass":表单面向的目标类,可以是实体类或者关联类。
"isRelation":关联类的数据形式特殊所以需要一个专门标记。
"basicArgs":表单的整体配置信息,包括:标签,布局的配置等。
"deviceType":表示表单是针对何种类型的终端设备。
在建模工具中编辑上述结构,保存以后,在表单引擎中解释这些结构,从而形成表单,接下来看如何编写表单控件的模型定制和应用前端程序。
2 表单控件的开发
接下来,通过逐步拆解一个入门控件的组成部分,展示一个文本框编辑表单控件的开发。
2.1 控件的建模端实现
控件的<template>标签
首先,看一下表单控件在建模工具中的几种关键表现形态
图-表单控件在建模时显示的内容
在表单建模工具内,一个表单控件会有三种展现形态
- 在控件栏内部的形态,一般表示为一个图标和文字,如上图所示
- 在放入表单开始准备编辑的状态,一般表示为一个可以点选的示意图的样子,这时候控件将显示成两部分
- 控件自身预览的样子
- 属性的设置区域显示的样子
因此,在表单控件的vue文件中的template部分一般包含3部分,对应到helloControl.vue文件,示例代码如下所示:
<template> <!-- 建模时的预览前端,即插件的实际显示样式:addinName="name"和ref="main"一般情况不可去除 --> <section v-if="t_preview" :addinName="name" ref="main"> <!-- 在画布区的显示内容 --> <span style="font-size: 50px; display: flex; justify-content: center; align-items: center;" > Hello World!</span> <!-- 在选项区的内容 --> <span v-show="t_edit" ref="edit"> </span> </section> <section v-else :addinName="name"> <!-- 如果上述条件均不满足的进入此处 --> </section> </template>
首先,在第一个section标签中:
t_preview:是一个开关变量,表单编辑工具将用其控制是否显示成图标样式,建模端的插件分为预览态和图标态,通过t_preview来区分,:addinName="name"和ref="main"一般情况不可去除。
在本章的例子中只需要显示一个居中的hello world!,所以放入了一个span标签并且手动设置了一个样式。
其次,在第一个section标签中,出现的另一个<span>依赖于t_edit变量控制,这是为了在控件被点击以后在右侧的配置区里展示的样子,在入门插件里没有任何配置项,所以只是给出一个空标签即可,在后续表单控件的进阶开发中将介绍如何利用DWF自动提供标准配置的编辑框。
最后,如果t_preview默认为false,此时表明表单建模工具希望得到控件的图标形态,所以第二个section的内容是是控件的中文名以及图标的形式<i>和名字显示方式<div>标签,这部分保持不变即可,
在<i>标签的图标使用的是字符配置形式,对照表可以参阅:图标对照页面。
控件的<script>标签
前面的建模标签描述了一个控件的基本组成部分,其中使用了t_preview与t_edit变量的绑定,用于设置样式,标签和标签内的属性。这些变量统一在vue文件的<script>部分,这部分内容包含一些控件和表单建模工具的交互过程。
在DWF表单建模工具内,data()函数返回控件的配置部分用JSON对象表示,该对象中需要返回的属性包括:
- name:控件的统一前缀,对应表单内部的id属性,表单建模工具也会以此名称在画布内初始化一个流水号作为控件的代号,这个代号将对应第三部分脚本中this.getAddinById的id。
- args:如果控件包含其他配置项用于描述其数据绑定,布局和显示样式则可以在这个对象里设置,args里必须包含一个title属性以便在表单控件树中显示,在进阶部分里会重点介绍如何设置args。
- 在上一节决定显示内容的t_preview和t_edit就在此函数内返回
此外,控件的id通过name属性返回,需要返回一个的函数是必须实现的,在methods内部需要实现:
- getFormName:如果控件需要绑定DWF数据模型中的数据属性则通过此函数返回名称。
- setArgs,getArgs:用于设置控件展示的参数,表单建模工具在读入表单配置对应的JSON或者在保存的时候会调用这两个函数。
- getEditBox:当需要显示配置区的设置项的时候会调用此函数,此时是将配置区显示出来的时候。
最后,表单控件的函数和vue整个生命周期函数调用的顺序是: created -> setArgs -> mounted,如果需要提前加载某些数据可以在create()里增加,在本章的例子中无需实现create和mounted。
下面,结合如下的代码在注释展现入门插件的脚本如下:
export default { // Vue数据绑定的时候要求返回的结果 data() { return { // 插件的名字 name: "helloControl", // 表示是否已经进入画布区 t_preview: true, // 是否显示控件的属性编辑区 t_edit: false, // 属性配置项,按需设置 args: { // 用于显示在表单控件树对应的标签,必须设置 title: "入门控件" }, }; }, methods: { // 默认不用变化,返回编辑框供建模工具绘制,当控件拖入画布区以后被点击的时候触发 getEditBox() { this.t_edit = true; return this.$refs.edit; }, // 现有表单加载在画布区加载控件的时候,会将之前的配置传入 setArgs(args) { for (var i in args) { this.args[i] = args[i]; } return this; }, // 表单保存的时候将控件的设置合并到表单自身的JSON中 getArgs() { return this.args; }, // 返回控件绑定的目标属性,如果没有绑定返回undefined或者null getFormName() { return this.args.name; }, }, };
控件的<style>标签
如果需要一些特殊的样式可以如下设置,本章的入门控件由于无需设置所以直接置空即可:
<style> </style>
最终合并结果
上述代码合并到helloControl.vue文件中的的结果如下:
<template> <!-- 建模时的预览前端,即插件的实际显示样式 :addinName="name"和ref="main"一般情况不可去除 --> <section v-if="t_preview" :addinName="name" ref="main"> <!-- 在画布区的显示内容 --> <span style=" font-size: 50px; display: flex; justify-content: center; align-items: center;" >Hello World!</span> <span v-show="t_edit" ref="edit"></span> </section> <section v-else :addinName="name"> </section> </template> <script> export default { // Vue数据绑定的时候要求返回的结果 data() { return { // 插件的名字 name: "helloControl", // 表示是否已经进入画布区 t_preview: true, // 是否显示控件的属性编辑区 t_edit: false, // 属性配置项,按需设置 args: { // 用于显示在表单控件树对应的标签,必须设置 title: "入门控件" }, }; }, methods: { // 默认不用变化,返回编辑框供建模工具绘制,当控件拖入画布区以后被点击的时候触发 getEditBox() { this.t_edit = true; return this.$refs.edit; }, // 现有表单加载在画布区加载控件的时候,会将之前的配置传入 setArgs(args) { for (var i in args) { this.args[i] = args[i]; } return this; }, // 表单保存的时候将控件的设置合并到表单自身的JSON中 getArgs() { return this.args; }, // 返回控件绑定的目标属性,如果没有绑定返回undefined或者null getFormName() { return this.args.name; }, }, }; </script> <style> </style>
对应的配置文件assemble-to.yaml文件内容如下:
config: ignore: info: part-web: name: modeler cname: 建模端 forms: helloControl.vue: from/single dependencies:
2.2 控件的应用端
应用端<template>标签
控件应用端负责根据建模端保存的配置信息,展示成预定的样子,因此不需要在<template>标签里再维护有关图标,配置的标签,只需要将表单引擎传递的配置信息反映在标签里即可。
针对我们即将实现的编辑框的例子,代码可以这么实现:
<template> <!-- 建模时的预览前端,即插件的实际显示样式 :addinName="name"和ref="main"一般情况不可去除 --> <section :addinName="name" ref="main"> <!-- 在画布区的显示内容 --> <span style=" font-size: 50px; display: flex; justify-content: center; align-items: center;" >Hello World!</span> </section> </template>
应用端的<script>标签
应用端插件开发必须实现3个函数:setDisplayType,setArgs,getArgs,作用如下:
- setDisplayType:在应用端表单引擎启动的时候会调用这个函数,并且传入一个参数type,告诉控件当前的表单希望以何种形态展示,type取值范围为 create, visit, edit。
- create创建态: 无数据,可编辑,visit浏览态: 有数据,不可编辑,edit编辑态: 有数据,可编辑
- setArgs,getArgs:表单引擎会将控件在建模工具中设置的参数传递到控件上。
此外,对于需要带入数据和配置的情况,表单引擎还会继续调用如下函数,在本章的helloControl例子中并不需要可以不实现:
- setError(error):设置异常状态显示
- validate() :设置校验逻辑,返回true/false
- getFormName() :返回对应的目标属性名称,引擎在渲染的时候将根据其返回值提取属性的取值调用setValue()
- getValue() :获取插件对应的值,一般为this.value,特殊情况下需要进行格式转化,如日期字符串
- setValue(items):设置插件对应的值, 如果目标属性为空,则传入的items为空,主要是针对多对象加载控件时使用,items目前为对应值,items将为目标对象列表,特殊情况下需要进行格式转化再赋值
最终,在APP端如果开发者关心DWF表单引擎和插件的的生命周期初始化顺序是:created -> setDisplayType -> setArgs -> setValue -> mounted,开发者可以酌情考虑添加对应的函数。
代码如下所示:
export default { // Vue数据绑定的时候要求返回的结果 data() { return { // 插件的名字 name: "helloControl", // 属性配置项,按需设置 args: { // 用于显示在表单控件树对应的标签,必须设置 title: "入门控件" }, }; }, methods: { /* type取值范围为 create, visit, edit 需要根据三个状态修改具体前端和逻辑 一般情况下: create创建态: 无数据,可编辑 visit浏览态: 有数据,不可编辑 edit编辑态: 有数据,可编辑 */ setDisplayType(type) { return this; }, //表单引擎加载到控件的时候调用此函数设置参数取值 setArgs(args) { for (var i in args) { this.args[i] = args[i]; } return this; }, // //表单引擎提取参数取值的方法 getArgs() { return this.args; }, }, };
应用端的<style>标签
由于本章并不需要特殊的样式标签,所以给出为空即可。
最终合并效果
上述3部分代码合并起来如下所示:
<template> <!-- 建模时的预览前端,即插件的实际显示样式 :addinName="name"和ref="main"一般情况不可去除 --> <section :addinName="name" ref="main"> <!-- 在画布区的显示内容 --> <span style=" font-size: 50px; display: flex; justify-content: center; align-items: center;" >Hello World!</span> </section> </template> <script> export default { // Vue数据绑定的时候要求返回的结果 data() { return { // 插件的名字 name: "helloControl", // 属性配置项,按需设置 args: { // 用于显示在表单控件树对应的标签,必须设置 title: "入门控件" }, }; }, methods: { /* type取值范围为 create, visit, edit 需要根据三个状态修改具体前端和逻辑 一般情况下: create创建态: 无数据,可编辑 visit浏览态: 有数据,不可编辑 edit编辑态: 有数据,可编辑 */ setDisplayType(type) { return this; }, //表单引擎加载到控件的时候调用此函数设置参数取值 setArgs(args) { for (var i in args) { this.args[i] = args[i]; } return this; }, // //表单引擎提取参数取值的方法 getArgs() { return this.args; }, }, }; </script> <style> </style>
在集成开发工具在默认状态下会将应用端和建模工具对应的端口变化为不同的端口号,所以直接分享的时候会出现404错误,如果发现此类问题,注意根据调试工具给出的端口号进行修改。
装配到应用端之后,通过表单分享得到的效果如下:
图-应用端表单分享的效果
3 表单控件调试和打包
如果需要发布此插件,可以利用装配脚本的generate指示符,生成代码包对应的zip文件,具体的调用方法如下:
PS D:\DWF3.0\scripts> python .\assemble.py generate 当前处于本地开发环境,仅支持代码打包和本地前端装配、卸载 ,请确认assemble-to.yaml填写正确 generateWithModel start generate part package part01 in D:\DWF3.0/dwf-part-all/zipfiles/part01.zip generateWithModel end PS D:\DWF3.0\scripts>
将part01.zip发往现场环境或者测试环境,在DWF的代码装配功能中即可获得入门插件。
3 小结
表单插件是DWF中最复杂的插件之一,包括模型定制和表单引擎两部分,本章主要介绍了表单插件的组成,生命周期,打包和调试方法,并给出了一个最简单的表单插件的开发方法。
在建模端,需要注意的实现要点如下:
- template标签中,需要提供画布预览、编辑区和图标状态的标签。
- script标签中
- data()返回需要给出一些基本属性:name,args,此外为了和标签配合,需要设置一些控制变量,例如t_preview,t_edit和args.title
- 需要提供如下的一些函数实现:getFormName,setArgs,getArgs,getEditBox。
在应用端,需要注意的实现要点如下:
- template标签中,只需要提供真实状态展示标签即可。
- script标签中,需要提供至少3个函数的实现:getFormName,setDisplayType,setArgs,getArgs。
调试中,DWFSDK需依靠assemble-to.yaml来实现自动装配,设置要点是:
- forms: 【vue文件】:【分类】, ...【vue文件】:【分类】
- dependencies: {【NPM包名】/【版本】,...}