VForm2开发者文档

/ 0条评论 / 0 个点赞 / 406人阅读

介绍

VForm2是一款基于Vue 2的低代码表单,支持Element UIiView两种UI库,定位为前端开发人员提供快速搭建表单、实现表单交互和数据收集的功能。

VForm由表单设计器VFormDesigner和表单渲染器VFormRender两部分构成,VFormDesigner通过拖拽组件方式生成JSON格式的表单对象,VFormRender负责将表单JSON渲染为Vue组件。


编译打包和项目集成

设计器VFormDesigner打包


  1. 运行 npm run lib 即可完成打包,内含v-form-designer、v-form-render两个组件,输出的库文件为如下两个:


(生成的文件有很多个,但是只需要这两个文件即可)

  1. 在项目根目录新建lib\vform,将上述两个文件复制到vform目录,目录结构如下所示:

  1. 修改main.js文件,引入组件:

import ElementUI from 'element-ui'  //引入element-ui库import 'element-ui/lib/theme-chalk/index.css'  //引入element-ui样式import vform from '../lib/vform/VFormDesigner.umd.min.js'import '../lib/vform/VFormDesigner.css'Vue.use(ElementUI)  //全局注册element-uiVue.use(vform)  //同时注册了v-form-designer、v-form-render等组件


渲染器VFormRender打包


提示:如果表单设计器(v-form-designer)和表单渲染器(v-form-render)在同一个项目中使用,并不需要单独打包渲染器,因为上述打包设计器生成的库文件已经包含v-form-render组件。

仅当表单渲染器和设计器在不同项目中使用时,才需要单独打包表单渲染器,单独打包的目的是为了降低所生成的库文件大小。

1.运行 npm run lib-render  即可完成打包,内含v-form-render组件,输出的库文件为如下两个:


2.修改main.js文件,引入组件:

import ElementUI from 'element-ui'  //引入element-ui库
import 'element-ui/lib/theme-chalk/index.css'  //引入element-ui样式

import VFormRender from '../lib/vform/VFormRender.umd.min.js'
import '../lib/vform/VFormRender.css'

Vue.use(ElementUI)  //全局注册element-ui
Vue.use(VFormRender)  //注册了v-form-render等组件


可能存在的问题及解决方法


如果自行编译打包在另一个Vue项目中引入后出现下述问题,或者Vue项目引入VForm后卡顿不能正常启动

可能原因有两个:babel没有设置忽略lib目录、eslint没有设置忽略lib目录。

(1) babel设置忽略lib目录,可以修改Vue项目的babel.config.js文件,如下所示:

![](./media/image (4).png)

(2) eslint设置忽略lib目录,在Vue项目根目录下新建.eslintignore文件,如下所示:



提示

如果以上方法都未生效,可以尝试删除node_modules目录内的.cache文件夹,然后重新启动该项目。

VForm组件接口文档

表单组件

表单设计器——VFormDesigner

属性(prop)
属性名称属性值说明默认值
field-list-api配置获取后端字段列表接口对象默认为null接口对象格式为:{  URL: '字段列表接口请求地址',  nameKey: 'fieldName',  labelKey: 'fieldLabel'}详情参见:字段接口文档
banned-widgets配置禁止设计器显示的组件默认为[],数据格式为组件type名称的数组,比如:['table', 'rate', 'switch']
designer-config配置设计器初始化界面显示设置默认值为:{//是否显示语言切换菜单languageMenu: true,//是否显示GitHub、文档等外部链接externalLink: true,//是否显示表单模板formTemplates: true,//是否禁止修改唯一名称widgetNameReadonly: false,//是否显示组件事件属性折叠面板eventCollapse: true,//是否显示清空设计器按钮clearDesignerButton: true,//是否显示预览表单按钮previewFormButton: true,//是否显示导入JSON按钮importJsonButton: true,//是否显示导出JSON器按钮exportJsonButton: true,//是否显示导出代码按钮exportCodeButton: true,//是否显示生成SFC按钮generateSFCButton: true,//工具按钮栏最大宽度(单位px)//如新增按钮后不可见,请调大//如右侧空白区域过大,请调小toolbarMaxWidth: 420,//工具栏按钮最小宽度(单位px)//值必须小于toolbarMaxWidthtoolbarMinWidth: 300,//表单设计器预设CSS代码presetCssCode: '',//表单设计器初始化自动清空内容/* 如设置为true,则刷新页面时也会清空设计器画布区域,慎用!*/resetFormJson: false,//设置自定义产品名称(仅Pro)productName: '',//设置自定义产品标题(仅Pro)productTitle: '',//是否显示顶部LOGO条(仅Pro)logoHeader: true,}
global-dsv全局数据源变量(Pro版支持)dsv即Datasource Variables(数据源变量)缩写。默认值为{},数据格式为:{  "myTestURL": "xxx",  "token": "aabbcc",  "countLimit": 600  //可以自由添加键值对}在数据源中可使用DSV["myTestURL"]、DSV["token"]、DSV["countLimit"]获取上述变量值。
插槽
名称说明
customToolButtons用于定制表单设计器的自定义工具按钮,位于默认工具按钮的右侧。
原生事件

原生事件可以在Vue模板中用@事件名称或JS代码中调用Vue实例的$on添加事件处理方法。

事件名称说明回调参数
暂无

交互事件

交互事件可在表单设计器中编写事件处理代码。

事件名称说明回调参数
暂无

API方法
方法名说明参数
changeLanguage修改界面显示语言string:'zh-CN'、'en-US'
setFormJson设置表单JSON对象string/object
getFormJson获取表单JSON对象
clearDesigner清空设计器画布
refreshDesigner刷新设计器画布(几乎用不到)
previewForm打开--预览表单--弹窗
importJson打开--导入表单JSON--弹窗
exportJson打开--导出表单JSON--弹窗
exportCode打开--导出Vue/HTML代码--弹窗
generateSFC打开--生成SFC组件代码--弹窗
getFieldWidgets获取表单JSON中的所有字段,返回对象数组,格式如下: [ { type: String, name: String, field: Object },  ..., ]— 无参数   注意:该方法获取的是formJson中的字段JSON定义,并非渲染后的字段组件。
getContainerWidgets获取表单JSON中的所有容器,返回对象数组,格式如下: [ { type: String, name: String, container: Object },  ..., ]— 无参数   注意:该方法获取的是formJson中的容器JSON定义,并非渲染后的容器组件。
getWidgetRef获取设计器组件实例(widgetName, showError): widgetName,组件名称 showError=true/false,如组件不存在是否显示错误
getSelectedWidgetRef获取设计器选中的组件实例



表单渲染器——VFormRender

属性(prop)
属性名称属性值说明默认值
form-json表单对象JSON  注意:如表单Json是从后端接口异步获取到的,请使用下述的API方法——setFormJson()赋值,使用form-json属性传值则会导致表单校验异常或表单渲染不成功。无默认值
option-data表单radio、checkbox、select、cascader组件的选择项集合默认值为空对象:{}, 属性值格式如下: {   'gender': [     {label: '男', value: '1'},     {label: '女', value: '2'}   ],   'paymentType': [     {label: '支付宝', value: 'alipay'},     {label: '微信', value: 'wechat'}   ] }
form-data表单数据对象  注意:form-data属性通常用于表单初始化时给表单传递回显数据,如需多次修改表单数据或发现表单部分数据失去响应式更新,请调用下述的setFormData(formData)方法。默认值为空对象:{}, 属性值格式如下: {   'gender': '2',   'paymentType': 'wechat'   'subForm01': [     {'price': '88.00', 'count': '12'},     {'price': '199.00', 'count': '16'}   ] }
global-dsv全局数据源变量(Pro版支持)  dsv即Datasource Variables(数据源变量)缩写。默认值为{},数据格式为: {   "myTestURL": "xxx",   "token": "aabbcc",   "countLimit": 600 }  在数据源中可使用 DSV["myTestURL"]、 DSV["token"]、 DSV["countLimit"] 获取上述变量值。
原生事件

原生事件可以在Vue模板中用@事件名称或JS代码中调用Vue实例的$on添加事件处理方法。

事件名称说明回调参数
buttonClickbutton组件被点击时触发 注意:如果button组件的交互事件onClick属性不为空,则不会触发buttonClick原生事件,两者不会同时生效。buttonWidget:被点击的按钮组件
appendButtonClickinput组件的附加按钮被点击时触发widget:input组件
formChange表单数据改变后触发(fieldName, newValue, oldValue, formModel, subFormName, subFormRowIndex): fieldName,触发本事件的字段名 newValue,字段新值 oldValue,字段旧值 formModel,表单数据对象  如果是子表单数据改变,则还会返回下述两个回调参数: subFormName, 子表单名称 subFormRowIndex, 子表单行索引
交互事件

交互事件可在表单设计器中编写事件处理代码。

事件名称说明回调参数
onFormCreated表单创建后触发
onFormMounted表单挂载后触发
onFormDataChange表单数据改变后触发(fieldName, newValue, oldValue): fieldName,触发本事件的字段名 newValue,字段新值 oldValue,字段旧值
API方法
方法名说明参数
changeLanguage修改界面显示语言string:'zh-CN'、'en-US'
setFormJson动态加载表单JSON对象string/object
getWidgetRef获取容器或字段组件(widgetName, showError): widgetName,组件名称 showError=true/false,如组件不存在是否显示错误
getNativeForm获取内嵌的el-form组件
validateForm表单数据是否验证通过callback(valid),回调函数,接受valid参数(true/false)
getFormData获取表单数据对象(needValidation = true),获取表单数据时是否开启表单校验,默认开启
setFormData设置表单数据对象formData,表单数据JSON对象
getFieldValue获取表单单个字段值fieldName,字段名称
setFieldValue设置表单单个字段值(fieldName, fieldValue):字段键值对
reloadOptionData刷新选项类型字段的选项数据(选项数据是从option-data属性传入的)widgetNames,组件名称,格式为字符串或字符串数组,不传该参数则刷新所有选项类型字段
getSubFormValues获取子表单数据对象subFormName,子表单名称
disableForm禁用表单编辑
enableForm启用表单编辑
resetForm重置表单数据,并清除校验状态
disableWidgets一个或多个组件禁用编辑widgetNames,组件名称,格式为字符串或字符串数组
enableWidgets一个或多个组件启用编辑widgetNames,组件名称,格式为字符串或字符串数组
hideWidgets隐藏一个或多个组件widgetNames,组件名称,格式为字符串或字符串数组
showWidgets显示一个或多个组件widgetNames,组件名称,格式为字符串或字符串数组
getFieldWidgets获取表单JSON中的所有字段,返回对象数组,格式如下: [ { type: String, name: String, field: Object },  ..., ]— 无参数   注意:该方法获取的是formJson中的字段JSON定义,并非渲染后的字段组件,如需获取字段组件,需要进一步调用getWidgetRef()方法。
getContainerWidgets获取表单JSON中的所有容器,返回对象数组,格式如下: [ { type: String, name: String, container: Object },  ..., ]— 无参数   注意:该方法获取的是formJson中的容器JSON定义,并非渲染后的容器组件,如需获取容器组件,需要进一步调用getWidgetRef()方法。
addEC增加外部组件实例引用,以便在VForm组件内部调用外部组件方法。  EC即external component(外部组件)缩写。(componentName, externalComponent): componentName, 外部组件名称 externalComponent, 外部组件实例
hasEC判断是否存在外部组件实例componentName, 外部组件名称
getEC获取外部组件实例componentName, 外部组件名称

容器组件

容器类型


功能对比

容器类型功能特点备注
栅格Grid支持24栅格列,可响应式布局,支持容器嵌套不可按像素指定宽度或高度
表格Table不支持响应式布局,可合并行或列,支持容器嵌套可按像素指定行高或列宽
页签Tab支持多页签展示内容,支持容器嵌套
卡片Card支持容器嵌套
子表单 SubForm单行式布局,不支持容器嵌套,只能嵌套字段组件支持多个子表单 (注:子表单组件包含在Pro版本中)
数据表格 DataTable多行多列展示数据(注:数据表格组件包含在Pro版本中)

交互事件

交互事件可在表单设计器中编写事件处理代码。

事件名称说明回调参数
onSubFormRowAdd子表单新增行时触发(subFormData, newRowId):新增后的子表单数据,新增行Id(非行索引)
onSubFormRowInsert子表单插入行时触发(subFormData, newRowId):插入后的子表单数据,插入行Id(非行索引)
onSubFormRowDelete子表单删除行时触发(subFormData, deletedDataRow):删除后的子表单数据,删除行数据
onSubFormRowChange子表单新增行、插入行、删除行时触发(subFormData):变化后的子表单数据

API 方法

方法名说明参数
getFormRef获取VFormRender组件
getWidgetRef获取容器或字段组件(widgetName, showError): 组件名称,如组件不存在是否显示错误
setHidden设置是否隐藏容器true/false
activeTab激活Tab页签指定页tabIndex:tab页索引
disableTab禁用Tab页签指定页tabIndex:tab页索引
enableTab恢复Tab页签指定页tabIndex:tab页索引
hideTab隐藏Tab页签指定页tabIndex:tab页索引
showTab显示Tab页签指定页tabIndex:tab页索引
disableSubFormRow禁用子表单指定行rowIndex:行索引
enableSubFormRow恢复子表单指定行rowIndex:行索引
disableSubForm禁用子表单
enableSubForm恢复子表单
resetSubForm重置子表单数据为空
getSubFormValues获取子表单数据

字段组件

字段组件类型

字段组件类型名

字段类型类型名(type)备注
单行输入input
多行输入textarea
计数器number
单选项radio
多选项checkbox
下拉选项select
时间time
时间范围time-range
日期date
日期范围date-range
开关switch
评分rate
颜色选择器color
滑块slider
静态文字static-text
HTMLhtml-text
按钮button
分隔线divider



图片picture-upload
文件file-upload
富文本rich-editor
级联选择cascader

交互事件

交互事件可在表单设计器中编写事件处理代码。

事件名称说明回调参数
onCreated组件创建后触发
onMounted组件挂载后触发
onClick按钮被点击触发
onInput输入框值改变时触发value:当前输入值
onChange组件数据(v-model)改变时触发(value, oldValue, subFormData, rowId): value,当前数据值 oldValue,变化之前的数据值  如果字段位于子表单内,还会返回下述两个回调参数: subFormData,组件所在子表单数据 rowId,组件所在子表单的行Id(非行索引)
onFocus获得焦点时触发event:事件
onBlur失效焦点时触发event:事件
onValidate组件数据校验时触发(rule, value, callback): rule,组件校验规则 value,组件数据值 callback,校验回调函数
onBeforeUpload图片或文件组件开始上传时触发file:上传文件
onUploadSuccess图片或文件组件上传成功后触发(result, file, fileList): result,上传处理结果 file,当前上传文件 fileList,上传文件列表
onUploadError图片或文件组件上传失败后触发(error, file, fileList): error,错误信息 file,当前上传文件 fileList,上传文件列表
onFileRemove删除图片或文件时触发(file, fileList): file,被删除文件 fileList,文件列表
onRemoteQuery下拉选项组件(Select)远程搜索时触发keyword:搜索词

API方法

方法名说明参数
getFormRef获取VFormRender组件
getWidgetRef获取容器或字段组件(widgetName, showError): widgetName,组件名称 showError=true/false,如组件不存在是否显示错误
setValue设置组件数据值newValue,组件数据值
getValue获取组件数据值
resetField重置组件为默认值,并清除组件校验状态
setReadonly设置组件是否只读,仅input、textarea、time、time-range、date、date-range等部分组件支持true/false
setDisabled设置组件是否禁用true/false
setAppendButtonVisible设置组件附加按钮是否可见,仅支持inputtrue/false
setAppendButtonDisabled设置组件附加按钮是否禁用,仅支持inputtrue/false
setHidden设置组件是否隐藏true/false
setRequired设置组件是否必填true/false
setLabel设置组件标签文字(label)newLabel,新标签文字
focus让组件获得输入焦点
loadOptions加载选择项,仅支持radio/checkbox/select/cascader组件options,选项数组,格式为: [ {label: '选项1', value: '1'}, {label: '选项2', value: '2'}, {label: '选项3', value: '3'} ]
getOptions返回radio/checkbox/select/cascader组件的选择项数组
disableOption禁用指定选择项,仅支持radio/checkbox/select/cascader组件optionValue,被禁用的选项值
enableOption启用指定选择项,仅支持radio/checkbox/select/cascader组件optionValue,被启用的选项值
setUploadHeader设置文件或图片组件请求头(Header)(name, value):请求头键值对
setUploadData设置文件或图片组件上传参数(name, value):参数键值对
setToolbar设置富文本组件默认工具栏按钮customToolbar,工具按钮数组,详细参见Vue2Editor文档
setWidgetOption设置组件属性(optionName, optionValue): optionName,组件属性名 optionValue,属性值
getFieldEditor获取组件内嵌的Element UI表单组件

表单设计的一般流程

1. 确定表单元素布局

选择合适的容器组件进行组合排放:栅格Grid、表格Table、标签页Tab、子表单SubForm;

2. 选择表单组件、排版定位

拖放合适的字段组件放置于容器组件合适的位置,并对字段组件命名,确保组件名称在当前表单中唯一;

3. 设置组件属性

如有需求,设置字段组件合适的属性或表单全局属性(注意:组件同名属性优先级高于表单全局属性);

4. 处理组件交互逻辑

如有需求,选择合适的组件事件,编写交互处理代码;

5. 设置组件自定义样式


如有需求,可添加表单CSS自定义样式,并在组件中应用自定义样式;


6. 导出表单代码


导出表单JSON代码应用于VFormRender组件,也可直接导出Vue组件代码或HTML源码,此外也支持生成SFC组件源码。


使用手册

后端集成

保存表单对象及渲染表单

保存表单对象


实现思路:

  1. 配置v-form-designer的customToolButtons插槽,新增一个“保存”按钮;

  2. 新增一个saveFormJson()方法,通过ref调用getFormJson()方法获取表单json对象,并提交给后台接口;

  3. 点击“保存”按钮时,调用上述saveFormJson()方法;

  4. 收工。

<template>  <div id="app">    <v-form-designer ref="vfDesigner" :field-list-api="fieldListApi" :banned-widgets="testBanned"                   :designer-config="designerConfig">      <!-- 自定义按钮插槽演示 -->      <template #customToolButtons>        <el-button type="text" @click="saveFormJson"><i class="el-icon-finished" />保存</el-button>      </template>    </v-form-designer>  </div></template><script>export default {  name: 'App',  data() {    return {      fieldListApi: {        URL: 'https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/listField',        labelKey: 'fieldLabel',        nameKey: 'fieldName'      },      testBanned: [        //'sub-form',        //'alert',      ],      designerConfig: {        languageMenu: true,        //externalLink: false,        //formTemplates: false,        //eventCollapse: false,        //clearDesignerButton: false,        //previewFormButton: false,        //presetCssCode: '.abc { font-size: 16px; }',      }    }  },  methods: {    saveFormJson() {      let formJson = this.$refs.vfDesigner.getFormJson()      //TODO: 将formJson提交给后端保存接口,需自行实现!!      this.$message.success('表单已保存!')    },  }}</script><style lang="scss">
  #app {    height: 100%;  }</style>


渲染表单


实现思路:
  1. 如表单中有保存于后端的选项数据(对应radio、check、select、cascader四类组件),从后端接口获取后赋值给v-form-render的option-data属性(可参见选项数据加载(opens new window));

  2. 如表单需要显示后端已保存的数据对象,从后端接口获取后赋值给v-form-render的form-data属性,如只需显示空白表单,则form-data属性可传入空对象{};

  3. 从后端接口获取表单json对象fjson,调用v-form-render对象的setFormJson(fjson)方法加载表单;

  4. 上述3步,应在mounted事件钩子中完成。如表单在对话框中显示,则以上3步,应在对话框显示之前完成;

  5. 完工。

<template>  <div>    <v-form-render :form-json="formJson" :form-data="formData" :option-data="optionData" ref="vFormRef">    </v-form-render>    <el-button type="primary" @click="submitForm">提交表单</el-button>  </div></template><script>  import axios from 'axios'  
  export default {    data() {      return {        formJson: {"widgetList":[],"formConfig":{"modelName":"formData","refName":"vForm","rulesName":"rules","labelWidth":80,"labelPosition":"left","size":"","labelAlign":"label-left-align","cssCode":"","customClass":"","functions":"","layoutType":"PC","onFormCreated":"","onFormMounted":"","onFormDataChange":"","onFormValidate":""}},        formData: {},        optionData: {}      }    },    mounted() {      //从后端接口获取表单的选项数据(如表单中无选项类型字段、则跳过此步骤),并赋值给optionData变量,需自行实现!!
      axios.get(SERVER_URL + '/get-option-data').then(res => {        if (res.code == 200) {          this.optionData = res.data        }        
        //从后端接口获取已保存的数据对象(如只显示空白表单、则跳过此步骤),并赋值给formData变量,需自行实现!!
        axios.get(SERVER_URL + '/get-form-data').then(res => {          let newFormData = null          if (res.code == 200) {
            newFormData = res.data          }          
          //从后端接口获取表单json对象,然后调用v-form-render对象的setFormJson(xxx)加载表单,需自行实现!!
          axios.get(SERVER_URL + '/get-form-json').then(res => {            if (res.code == 200) {              this.$refs.vFormRef.setFormJson(res.data)              this.$nextTick(() => {                this.$refs.vFormRef.setFormData(newFormData)              })            }          }).catch(err => {            //          })        }).catch(err => {          //        })      }).catch(err => {        //      })    },    methods: {      submitForm() {        this.$refs.vFormRef.getFormData().then(formData => {          // Form Validation OK          alert( JSON.stringify(formData) )        }).catch(error => {          // Form Validation failed          this.$message.error(error)        })      }    }  }</script><style scoped></style>


设计器集成后端字段接口

可以从后端获取到字段信息,用于表单数据绑定。

查询单表


可以查询指定单个表格的数据

选择单表数据,然后选择对应的数据库表

唯一名称 字段可以绑定前面所选数据库表的字段


查询主从表


表结构选择主从表单,主表只能选择一个,从表可以添加多个。 从表表名:所选择的数据库从表的表名 外键字段:所选择的数据库从表的主键 关联主键:主表的主键(无需手动选择)

在单行子表单组件中选择要绑定的数据库表

子表单内的表单项就可以选择所选表的字段

效果演示


表单的状态控制


通常来讲,表单会有三种状态:新建、编辑、查看,大体对应CRUD中的三种业务逻辑,即Create、Update、Read。

表单在新建状态、编辑状态,数据绑定字段都是可操作、可录入的,新建和编辑的差别在于表单数据对象的id是否有值。通常新建表单的数据提交到后端,由后端负责生成id值,编辑时读取后端接口,返回的数据对象包含id值。

因此要区分表单的新建和编辑状态就变得很简单,只需要在表单中增加一个单行输入字段,并将字段唯一名称设置为后端对应的id属性名称,然后将该字段设置为隐藏,相当于在表单中增加了一个id隐藏字段,如下图所示:


新建状态表单操作
  1. 首先调用后端新建接口(如果有的话,没有则不调用),获取到表单数据对象formData;

  2. 调用setFormData(formData)方法,完成新建状态的表单数据展示;

  3. 点击表单提交按钮,调用getFormData()方法,利用axios跟后端接口交互,将表单数据保存到数据库。

编辑状态表单操作

操作基本同上,区别在于从后端获取到的formData对象包含id值。

  1. 首先调用后端数据读取接口,获取到表单数据对象formData;

  2. 调用setFormData(formData)方法,完成编辑状态的表单数据展示;

  3. 点击表单提交按钮,调用getFormData()方法,利用axios跟后端接口交互,将表单数据保存到数据库。

查看状态表单操作
  1. 首先调用后端数据读取接口,获取到表单数据对象formData;

  2. 调用setFormData(formData)方法,加载表单数据展示;

  3. 接着调用disableForm()方法,将表单设置为禁止编辑状态;

  4. 如需从查看状态切换到编辑状态,则调用方法enableForm()。

栅格布局与表格布局

栅格布局


通过标准的24分栏,可以简单快捷地创建表单布局,轻松实现单列、两列、三列、四列排版布局。

栅格分栏之间可以设置间隔,栅格宽度根据父容器宽度自适应。

栅格布局可以嵌入字段组件或其他容器组件。

栅格内嵌套另一个栅格,可以实现类似于表格的合并行效果。


表格布局


类似于Excel的表格,可以实现行、列合并,可以指定单元格的行高、列宽。

表格布局可以嵌入字段组件或其他容器组件。


栅格容器与多终端响应式布局


  1. 效果演示动图

  1. 设置方法

通过开启栅格容器中栅格列的“响应式布局”属性,可以实现多终端的响应式布局适配。

栅格容器整行宽度共24栅格,因此栅格宽度设置为8占据三分之一行宽,设置为12则占据一半行宽,设置为24占据整行宽度。

a. 适配PC终端(视口像素宽度 = 992px):

b. 适配Pad终端(768px <= 视口像素宽度 < 992px):

c. 适配H5终端(视口像素宽度 < 768px):

  1. 可能存在的问题及解决方法

当栅格列设置为响应式布局后,栅格列会被追加float样式(float: left),如同一栅格布局内多个栅格列的默认高度不一致时,则会导致布局错位,如下图所示:

解决方法:

给栅格布局设置栅格列统一高度即可解决(单位为像素),如下图所示:


表单及组件属性设置

表单属性设置

包含表单基本属性、事件属性设置。

组件属性设置

栅格容器与多终端响应式布局


组件拥有丰富的可设置属性,大部分情况下使用组件的默认属性就能很好地完成工作,一般只需要设置组件名称(确保名称唯一)、字段标签、数据校验规则,如果有交互逻辑则编写事件属性的处理代码。

组件基本属性:

注意:组件的同名属性优先级高于表单属性,比如字段标签对齐方式、组件大小、标签宽度。

组件高级属性,默认为收起状态:

组件事件属性:


数据校验

字段的数据校验支持三种校验方式:是否必填校验、正则表达式校验、自定义校验。

必填校验


方法一:通过表单设计器的字段属性设置面板,设置“必填字段”属性为选中状态;


方法二:可以调用组件的API方法setRequired(true/false),动态设置组件是否必填;

正则表达式校验

通过表单设计器的字段属性设置面板,设置“字段校验”属性,该属性内嵌了几种常见的正则校验(实现代码在src/utils/validators.js),该属性也可以输入自定义的正则表达式文本(输入后请按回车键确认);

设置“校验失败提示”属性,填入校验失败提醒内容。



自定义校验


选中字段后,在表单设计器的字段属性设置面板选择事件属性“onValidate”,编写校验代码。

如下示例代码,可校验字段值是否介于0~100,超出范围则校验失败:

  if (value === '') { //空值不校验    callback()    return  }  
  if ((value  100) || (value < 0)) {    callback(new Error('error message'))  //校验失败  } else {    callback();  //校验通过  }


选择项设置与加载

此处的选择项是指radio单选项、checkbox多选项、select下拉选项以及cascader级联选择组件的可选择项目。

选择项支持3种设置方法:

使用表单设计器管理选择项


表单设计阶段,可通过组件属性设置面板操作:


提示:

可以批量导入选择项,每一行以英文逗号分隔,如不包含英文逗号,则选择项的value和label同值:


使用API方法动态加载选择项


表单运行阶段,可调用组件自身的API方法loadOptions(options)动态加载选择项,选择项格式为:

[{label: '选项1', value: '1'},{label: '选项2', value: '2'},{label: '选项3', value: '3'}]

示例:

在表单的 onFormMounted 事件中通过axios调用后端接口,动态加载产品类型,代码如下图:

运行效果如下图:

表单JSON如下,复制JSON,在表单设计器中选择“导入JSON”即可看到效果:

{  "widgetList": [    {      "type": "select",      "icon": "select-field",      "formItemFlag": true,      "options": {        "name": "productType",        "label": "产品类型",        "labelAlign": "",        "defaultValue": "",        "placeholder": "",        "columnWidth": "200px",        "size": "",        "labelWidth": null,        "labelHidden": false,        "disabled": false,        "hidden": false,        "clearable": true,        "filterable": false,        "allowCreate": false,        "remote": false,        "automaticDropdown": false,        "multiple": false,        "multipleLimit": 0,        "optionItems": [],        "required": false,        "validation": "",        "validationHint": "",        "customClass": "",        "labelIconClass": null,        "labelIconPosition": "rear",        "labelTooltip": null,        "onCreated": "",        "onMounted": "",        "onRemoteQuery": "",        "onChange": "",        "onFocus": "",        "onBlur": "",        "onValidate": ""      },      "id": "select87612"    }  ],  "formConfig": {    "labelWidth": 80,    "labelPosition": "left",    "size": "",    "labelAlign": "label-left-align",    "cssCode": "",    "customClass": "",    "functions": "",    "layoutType": "PC",    "onFormCreated": "",    "onFormMounted": "  let productTypeR = this.getWidgetRef('productType')\n  \n  axios.get(\"https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/getOptions\").then(function(res) {\n    //console.log(res.data)\n    productTypeR.loadOptions(res.data)\n  }).catch(function(error) {\n    console.log(error)\n  })",    "onFormDataChange": ""  }}


使用表单option-data属性导入选择项


表单运行阶段,通过VFormRender的option-data属性一次性导入多个组件的选择项,属性值格式为:

{  'gender': [

    {label: '男', value: '1'},

    {label: '女', value: '2'}  ],  'paymentType': [

    {label: '支付宝', value: 'alipay'},

    {label: '微信', value: 'wechat'}  ]}

需要注意的是,option-data属性加载的选择项不是响应式更新的,仅在表单初始化时被组件加载,因此当option-data属性指向的选择项数据有更新后,应该手动调用v-form-render组件的reloadOptionData方法刷新。


使用数据源加载选择项

VForm Pro提供了选项的数据源配置功能:参考第9点(数据源管理)

图片与文件上传

图片、文件上传一般由前端上传到后端服务器中

上传后端服务器


  1. 获取到后端服务器的上传地址,默认值:/api/FormFileUpload/UploadFile


  1. 后端接口在处理文件上传时,如果需要获取上传请求的cookie信息,则需要选中“发送cookie凭证”,默认选中



子表单


子表单是一种实现一对多关系中明细数据展示、编辑的容器组件。

子表单内只能放置字段组件,不能放置其他容器组件。

一个表单可以包含多个子表单组件。

子表单支持交互事件和API方法,可以实现复杂的交互逻辑。

通过交互事件和API方法,可实现子表单的自动更新小计和累计功能


交互事件

交互事件可在表单设计器中编写事件处理代码。

事件名称说明回调参数
onSubFormRowAdd子表单新增行时触发(subFormData, newRowIndex): 新增后的子表单数据,新增行索引
onSubFormRowInsert子表单插入行时触发(subFormData, newRowIndex): 插入后的子表单数据,新增行索引
onSubFormRowDelete子表单删除行时触发(subFormData, deletedDataRow): 删除后的子表单数据,删除行数据
onSubFormRowChange子表单新增行、插入行、删除行时触发(subFormData): 变化后的子表单数据

API方法

方法名说明参数
getFormRef获取VFormRender组件
getWidgetRef获取容器或字段组件(widgetName, showError): 组件名称,如组件不存在是否显示错误
setHidden设置是否隐藏容器true/false
disableSubFormRow禁用子表单指定行rowIndex:行索引
enableSubFormRow恢复子表单指定行rowIndex:行索引
disableSubForm禁用子表单
enableSubForm恢复子表单
resetSubForm重置子表单数据为空
getSubFormValues获取子表单数据

数据表格

数据表格data-table是对el-table组件和el-pagination组件的封装,实现了数据表格的可视化设计,主要用于大数据量的展示场景。

效果展示


1表格可视化设计

2表格列编辑,可拖拽调整列顺序

3操作按钮设置


原生事件

原生事件可以在Vue模板中用@事件名称或JS代码中调用Vue实例的$on添加事件处理方法。

事件名称说明回调参数
dataTablePageSizeChange分页大小改变时触发(dataTable, pageSize, currentPage): dataTable,数据表格组件实例 pageSize,分页大小 currentPage,当前页码
dataTablePageChange页码改变时触发(dataTable, pageSize, currentPage): dataTable,数据表格组件实例 pageSize,分页大小 currentPage,当前页码
dataTableSelectionChange选择记录改变时触发(dataTable, selection, selectedIndices): dataTable,数据表格组件实例 selection,选中记录 selectedIndices,选中行索引数组
operationButtonClick操作按钮点击时触发(dataTable, buttonName, rowIndex, row): dataTable,数据表格组件实例 buttonName,被点击按钮名称 rowIndex,被点击按钮所在行索引 row,被点击按钮所在行数据对象

交互事件

交互事件可在表单设计器中编写事件处理代码。

注意:对于同一事件名称,交互事件和原生事件不会同时触发,交互事件处理代码的执行优先级高于原生事件。

事件名称说明回调参数
onPageSizeChange选择记录改变时触发(pageSize, currentPage): pageSize,分页大小 currentPage,当前页码
onCurrentPageChange页码改变时触发(pageSize, currentPage): pageSize,分页大小 currentPage,当前页码
onSelectionChange选择记录改变时触发(selection, selectedIndices): selection,选中记录 selectedIndices,选中行索引数组
onOperationButtonClick点击操作按钮触发(buttonName, rowIndex, row): buttonName,被点击按钮名称 rowIndex,被点击按钮所在行索引 row,被点击按钮所在行数据对象
onHideOperationButton设置操作按钮是否隐藏时回调 注意:该回调事件必须返回true或false,以控制按钮隐藏或显示。(buttonConfig, rowIndex, row): buttonConfig,按钮配置对象 rowIndex,按钮所在行索引 row,按钮所在行数据对象
onDisableOperationButton设置操作按钮是否禁用时回调 注意:该回调事件必须返回true或false,以控制按钮隐藏或显示。(buttonConfig, rowIndex, row): buttonConfig,按钮配置对象 rowIndex,按钮所在行索引 row,按钮所在行数据对象
onGetOperationButtonLabel设置操作按钮label时回调 注意:该回调事件必须返回字符串类型。(buttonConfig, rowIndex, row): buttonConfig,按钮配置对象 rowIndex,按钮所在行索引 row,按钮所在行数据对象
onHeaderClick列表头点击时触发(column, event): column,点击位置所在列 event,点击事件
onRowClick行点击时触发(row, column, event): row,点击位置所在行 column,点击位置所在列 event,点击事件
onRowDoubleClick行双击时触发(row, column, event): row,点击位置所在行 column,点击位置所在列 event,点击事件
onCellClick单元格点击时触发(row, column, cell, event): row,点击位置所在行 column,点击位置所在列 cell,点击位置所在单元格 event,点击事件
onCellDoubleClick单元格双击时触发(row, column, cell, event): row,点击位置所在行 column,点击位置所在列 cell,点击位置所在单元格 event,点击事件
onGetRowClassName获取行css样式名称时回调 注意:该回调事件必须返回字符串类型,即行css样式名称。 此外还需注意:如果开启了斑马线效果,则斑马线效果优先级更高。(row, rowIndex): row,行 rowIndex,行索引
onGetSpanMethod合并单元格时回调 注意:该回调事件必须返回数组或对象,详情请参见element-ui组件库el-table的具体使用文档: 点此打开(opens new window)(row, column, rowIndex, columnIndex): row,行 column,列 rowIndex,行索引 columnIndex,列索引

API方法

方法名说明参数
getFormRef获取VFormRender组件
getWidgetRef获取容器或字段组件(widgetName, showError): 组件名称,如组件不存在是否显示错误
setHidden设置是否隐藏容器true/false
———————————————————————————
setTableColumn设置表格列对象tableColumns, 数据格式参见widgetsConfig.js
setTableData设置表格数据tableData, 数据格式参见widgetsConfig.js
getTableData获取表格数据
setPagination设置分页对象pagination,数据格式为: {   currentPage: 1,   pageSize: 15,   total: 188 }
getSelectedRow获取选中行数据,返回对象数组
getSelectedIndex获取选中行索引,返回数组
setTableColumnsHidden设置列隐藏或显示(columnNames, hiddenFlag): columnNames,列名称,字符串或字符串数组 hiddenFlag,true隐藏,false显示
loadColumnsFromDS从数据源加载表格列(localDsv, dsName): localDsv,本地数据源变量,默认值为空对象{},本地数据源变量自动和全局数据源合并后传递给数据源 dsName,数据源名称,无默认值
loadDataFromDS从数据源加载表格数据(localDsv, dsName): localDsv,本地数据源变量,默认为空对象{},本地数据源变量自动和全局数据源合并后传递给数据源 dsName,数据源名称,默认值为空字符串,不传此参数则使用表格绑定的数据源

数据源


数据表格支持绑定数据源,绑定数据源后,表格数据首次加载、改变分页大小、翻页时会自动执行数据源请求,从后端获取表格数据。

需要注意的是,数据表格在执行数据源请求时,会自动给全局数据源变量DSV绑定pageSize、currentPage两个变量值,在设置数据源时可通过DSV['pageSize']、DSV['currentPage']获取变量值。


数据源管理


数据源是VForm对动态获取后端数据功能的一种封装,基于axios实现,使用非常简单方便,支持数据源变量(DSV),具备相当的灵活性


数据源属性说明


唯一名称:必填属性,是数据源的唯一标识,建议使用大小写字母、数字进行组合;

请求地址:即后端接口的URL,支持字符串常量或变量表达式;

变量表达式,是指可以用DSV对象属性(或VFR对象)和其他字符串进行拼接运算,比如:

DSV['API_SERVER'] + '/getCityList'

DSV对象,一般通过v-form-designer或v-form-render的global-dsv属性传值进来

VFR对象,即v-form-render组件实例,可以调用其API方法

描述信息:补充说明数据源的功能或使用要求,在选择数据源时作为参考;

请求方法:对应get、post、put、delete;

请求头(headers):对应axios的headers属性,支持变量表达式,可从DSV中取值;

参数(params):对应axios的params属性,支持变量表达式,可从DSV中取值;

发送数据(data):对应axios的data属性,支持变量表达式,可从DSV中取值;

请求配置:是一个回调函数,可以在发送请求之前再次修改config对象,参数说明如下:

config,是上述headers、params、data等属性的组合对象

isSandbox,是否测试数据源状态,测试数据源是为true,其他状态为false

DSV,数据源变量对象,通过v-form-designer或v-form-render的global-dsv属性传值进来

VFR,即v-form-render组件实例,可以调用其API方法

数据处理:是一个回调函数,可以对获取到的数据结果进行加工处理,参数说明如下:

result,是axios请求返回的result对象

isSandbox,是否测试数据源状态,测试数据源是为true,其他状态为false

DSV,数据源变量对象,通过v-form-designer或v-form-render的global-dsv属性传值进来

VFR,即v-form-render组件实例,可以调用其API方法

错误处理:是一个回调函数,当axios请求发送错误进行处理,参数说明如下:

error,是axios请求发生错误时error对象

isSandbox,是否测试数据源状态,测试数据源是为true,其他状态为false

DSV,数据源变量对象,通过v-form-designer或v-form-render的global-dsv属性传值进来

$message,VForm的全局message对象,可用于前端消息提示。

VFR,即v-form-render组件实例,可以调用其API方法。


测试数据源


DSV数据源变量:默认显示是通过global-dsv属性传递的数据,在测试数据源时DSV是可以修改的。

值得注意的是,给DSV增加新的键值对,其属性名称必须以双引号包括(这可能是AceEditor编辑器的要求)。

此外还有一点需要提示,测试数据源时,isSandBox的值为true,这个参数会传递给上述的请求配置、数据处理和错误处理三个回调函数。

当数据源绑定到组件上时,组件请求数据源时,会自动给DSV对象增加一个键值对,格式如下:

widgetName: '组件唯一名称'

那么DSV.widgetName在设置数据源时可作为变量表达式使用;很明显,在测试数据源的时候,DSV对象是没有widgetName属性值的,这意味着如果你在数据源中使用了DSV.widgetName变量表达式,那么测试数据源的时候需要你手工为DSV对象增加widgetName键值对,如下所示:

{  /* 略过DSV已有数据... */  "widgetName": 'userNameInput'}


如何传递请求token


通过v-form-designer或v-form-render的global-dsv属性传递,比如给globalDsv对象增加一个token:

{  "token": '8888aaaa000xxxxcccc6666'}

那么在数据源设置时,就可以通过DSV.token获取到该值。

注意:global-dsv属性是响应式更新的,这意味着globalDsv对象中的值可以动态修改,数据源在执行时总是使用globalDsv最新的数据。


为组件绑定数据源


目前支持数据源绑定的组件有:单选项radio、多选项checkbox、下列选项select、级联选择cascader以及数据表格data-table。


自定义CSS样式


自定义样式在表单运行期间生效,可以覆盖表单或组件原有样式。

自定义样式会被添加到页面的style节点,全局生效。

添加自定义样式时,应注意样式class名称不要与已有样式名称冲突。


重要提示


自定义CSS样式代码会被直接插入到文档对象document的style节点,不存在转译过程,因此不支持SCSS或LESS语法,请按浏览器标准编写CSS样式代码。

如需将SCSS转译为CSS代码,可使用这个在线转译网站:

https://www.sassmeister.com/


示例


下面通过添加自定义样式,将必填字段的label设置为粗体。

1添加表单全局CSS代码,如下所示:

2选中字段,并设置必填属性,然后在字段的高级属性“自定义CSS样式”选择“bold-label”:

3预览后即可看到效果:


自定义函数


在组件的交互事件中,为了实现预期的效果,可能会多次编写大量重复代码,这时候可以将重复代码提取出来,变成一个独立的自定义函数,方便在交互事件中多次调用。

提示:

  1. 需要注意的是,自定义函数会被追加到window对象,变成全局函数,所以命名上应考虑不会与其他全局函数名称冲突;

  2. 自定义函数在表单运行期间执行,javascript代码不会经历Babel编译这一步,如果需要在IE 浏览器中正常运行,请按IE 浏览器的javascript兼容语法编写自定义函数。


调试交互事件JavaScript代码


交互事件的JS代码在表单运行期间执行,执行原理是:通过Function对象创建一个匿名函数,传入事件参数后执行。

如果交互事件中编写了较多代码,一旦代码没有实现预定逻辑,则需要对代码进行调试,这时候可以用debugger关键字:在需要插入断点的位置输入“debugger”,则浏览器执行到此处代码时会自动进入调试状态。


示例


演示效果:当单选项点击后,获取到当前点击值后,然后进入调试状态,查看当前点击值

在单选项组件的onChange事件处理代码合适的位置加入debugger关键字:

预览表单、并按F12键打开Chrome开发者工具,然后点击单选项组件,即刻进入了调试状态:

可以看到事件处理代码被封装在一个匿名函数中运行,函数中包含事件传入的各个参数,当前断点停留于debugger位置,可以查看变量值,或者继续往下调试执行代码。


前端代码生成


VForm 2支持三种前端代码生成:Vue组件、HTML源码、SFC组件,以下对三种生成的代码进行简单对比。

代码类型依赖包备注
Vue组件vue2、element-ui、variant-form适合Vue2项目
HTML源码vue2、element-ui、variant-form适合历史遗留Web项目
SFC组件Vue2版vue2、element-ui适合Vue2项目
Vue3版vue3、element-plus适合Vue3项目

根据上表对比可以发现,生成的SFC组件代码可以脱离VForm运行,因为SFC组件相当于把JSON表单转化为手写的vue2 + element-ui代码或vue3+ element-plus代码。

SFC组件和Vue组件(含HTML源码)的区别在于,SFC组件失去了动态表单的所有功能,包括交互逻辑控制、API方法调用、事件响应等等,无法满足在运行时变更表单的需求。


VS Code插件


vform-maker是Variant Form的VS Code插件实现。vform-maker提供可视化的表单设计功能,支持一键导出为Vue2或Vue3代码,为前端开发提效,轻松享受更多摸鱼时间。

安装

在VS Code扩展搜索vform-makervformAdmin即可找到该插件,秒速安装!


二次开发指南

二次开发说明

VForm源码目录结构说明

二次开发文档目录结构


1. 容器组件开发  1.1 定义容器JSON Schema  1.2 开发设计状态的容器组件    1.2.1 容器组件SFC文件编写    1.2.2 插入Draggable组件    1.2.3 接收组件拖放事件    1.2.4 创建并注册组件属性设计器  1.3 开发运行状态的容器组件    1.3.1 容器组件SFC文件编写    1.3.2 增加交互事件和API方法  
2. 字段组件开发  2.1 定义字段JSON Schema  2.2 字段组件SFC文件编写  2.3 创建并注册组件属性设计器  2.4 增加交互事件和API方法  
3. 代码自动生成


VForm组件⼆次开发指南


VForm的组件库分为两类,第⼀类是容器组件,主要负责表单元素的布局排列,第⼆类为字段组件,主

要负责数据收集或内容展示。容器组件可以嵌套其他容器或字段组件,字段组件可以放置于容器之内或

者表单上(即整个表单也相当于⼀个⼤容器)。


容器组件开发


  1. ⾸先拉取VForm源码:

  2. VS Code导⼊源码项⽬,并执⾏ npm install 安装依赖包,安装依赖完成之后执⾏ npm run serve

进⼊开发模式;

  1. 打开 src/extension/sample/extension-schema.js,可看到card容器定义的JSON Schema如下:

export const cardSchema = { type: 'card', category: 'container', icon: 'card', widgetList: [], options: { name: '', label: 'card', hidden: false, cardWidth: '100%', //卡⽚宽度,百分⽐或像素宽度 shadow: 'never', //是否显示阴影 customClass: '', //⾃定义css样式 }}

JSON Schema解释说明:

type:容器组件的类型名称,必须唯⼀,不能跟已有组件重复;

icon:容器图标名称,可以去iconfont.cn下载所需的svg⽂件,放⼊src/icons/svg⽬录即可(⾃动加

载);

category:容器组件必须设置为'container';

widgetList:容器内存放的组件列表,初始值必须为[];

options:组件属性对象,每⼀个属性值对应⼀个属性编辑器。

  1. 编写card容器的SFC组件⽂件,容器组件对应两个状态:设计期状态可以接收组件拖拽,运⾏期状

态负责组件渲染,所以需要编写两个SFC⽂件,命名规则需严格遵守:容器名称-widget(设计

期)、容器名称-item(运⾏期);

card-widget.vue代码如下:

<template>  <container-wrapper :designer="designer" :widget="widget" :parent-widget="parentWidget" :parent-list="parentList"                     :index-of-parent-list="indexOfParentList">    <el-card :key="widget.id" class="card-container" @click.native.stop="selectWidget(widget)"             :shadow="widget.options.shadow" :style="{width: widget.options.cardWidth + '!important' || ''}"             :class="[selected ? 'selected' : '', customClass]">      <div slot="header"><span>{{widget.options.label}}</span></div>      <draggable :list="widget.widgetList" v-bind="{group:'dragGroup', ghostClass: 'ghost',animation: 200}"
                 handle=".drag-handler"
                 @add="(evt) => onContainerDragAdd(evt, widget.widgetList)"
                 @update="onContainerDragUpdate" :move="checkContainerMove">        <transition-group name="fade" tag="div" class="form-widget-list">          <template v-for="(subWidget, swIdx) in widget.widgetList">            <template v-if="'container' === subWidget.category">              <component :is="subWidget.type + '-widget'" :widget="subWidget" :designer="designer" :key="subWidget.id" :parent-list="widget.widgetList"                         :index-of-parent-list="swIdx" :parent-widget="widget"></component>            </template>            <template v-else>              <component :is="subWidget.type + '-widget'" :field="subWidget" :designer="designer" :key="subWidget.id" :parent-list="widget.widgetList"                         :index-of-parent-list="swIdx" :parent-widget="widget" :design-state="true"></component>            </template>          </template>        </transition-group>      </draggable>    </el-card>  </container-wrapper></template>

封装了Element UI的el-card组件,重点看4~7⾏代码,如何跟JSON Schema的属性进⾏结合,其他部分代码复制粘贴即可。

card-item.vue代码如下:

<template>  <container-item-wrapper>    <el-card :key="widget.id" class="card-container" :class="[customClass]"             :shadow="widget.options.shadow" :style="{width: widget.options.cardWidth + '!important' || ''}"             :ref="widget.id" v-show="!widget.options.hidden">      <div slot="header"><span>{{widget.options.label}}</span></div>      <template v-if="!!widget.widgetList && (widget.widgetList.length > 0)">        <template v-for="(subWidget, swIdx) in widget.widgetList">          <template v-if="'container' === subWidget.category">            <component :is="subWidget.type + '-item'" :widget="subWidget" :key="swIdx" :parent-list="widget.widgetList"                       :index-of-parent-list="swIdx" :parent-widget="widget"></component>          </template>          <template v-else>            <component :is="subWidget.type + '-widget'" :field="subWidget" :designer="null" :key="swIdx" :parent-list="widget.widgetList"                       :index-of-parent-list="swIdx" :parent-widget="widget"></component>          </template>        </template>      </template>    </el-card>  </container-item-wrapper></template>

重点看3-6⾏代码,其他部分代码复制粘贴即可。

  1. 加载options对应的属性编辑器,对应表单设计器右侧的SettingPanel⾯板,具体代码参⻅

extension-loader.js:

  PERegister.registerCPEditor('cardWidth', 'card-cardWidth-editor',
      PEFactory.createInputTextEditor('cardWidth', 'extension.setting.cardWidth'))  let shadowOptions = [    {label: 'never', value: 'never'},    {label: 'hover', value: 'hover'},    {label: 'always', value: 'always'},  ]
  PERegister.registerCPEditor('shadow', 'card-shadow-editor',
      PEFactory.createSelectEditor('shadow', 'extension.setting.cardShadow',          {optionItems: shadowOptions}))

代码解释:此处只加载了cardWidth、shadow两个属性的编辑器组件,因为其他属性编辑器在VForm框

架内已经预先加载了。以上使⽤到的字符串资源分别位于src\lang\zh-CN_extension.js、

src\lang\en-US_extension.js两个⽂件中。

  1. 容器组件开发完毕,扩展组件的加载由extension-loader.js的loadExtension()⽅法执⾏,该⽅法在

main.js中被调⽤。


字段组件开发


本节通过开发一个简单的alert组件讲解如何实现字段组件、静态内容组件的扩展开发。

步骤1、2同上。

  1. 打开 src/extension/sample/extension-schema.js,可看到alert组件定义的JSON Schema如下:

export const alertSchema = {  type: 'alert',  icon: 'alert',  formItemFlag: false, //是否需嵌套于el-form-item  options: {    name: '',    title: 'Good things are coming...',    type: 'info',    description: '',    closable: true,    closeText: '',    center: true,    showIcon: false,    effect: 'light',    hidden: false,    onClose: '',    customClass: '',  }}

JSON Schema解释说明:

type:字段组件的类型名称,必须唯一,不能跟已有组件重复;

icon:容器图标名称,可以去iconfont.cn下载所需的svg文件,放入src/icons/svg目录即可(自动加载);

formItemFlag:是否嵌套于el-form-item组件内,因el-alert并不需要显示字段标签,故此处设置为false;

options:组件属性对象,每一个属性值对应一个属性编辑器。

  1. 编写字段组件的SFC文件,字段组件在设计期和运行期共用,故只需要编写一个SFC文件,命名规则需严格遵守:组件名称-widget。

<template>  <static-content-wrapper :designer="designer" :field="field" :design-state="designState"                          :parent-widget="parentWidget" :parent-list="parentList" :index-of-parent-list="indexOfParentList"                          :sub-form-row-index="subFormRowIndex" :sub-form-col-index="subFormColIndex" :sub-form-row-id="subFormRowId">    <el-alert ref="fieldEditor" :title="field.options.title" :type="field.options.type"              :description="field.options.description" :closable="field.options.closable"              :center="field.options.center" :close-text="field.options.closeText"              :show-icon="field.options.showIcon" :effect="field.options.effect" @close="handelCloseCustomEvent"></el-alert>  </static-content-wrapper></template><script>  //...    methods: {      handelCloseCustomEvent() {        if (!!this.field.options.onClose) {          let closeFn = new Function(this.field.options.onClose)          closeFn.call(this)        }      }    }  //...</script>

因为formItemFlag设置为false,故此处必须使用static-content-wrapper包裹组件(如formItemFlag设置为true,则应使用form-item-wrapper包裹组件),5~8行代码对应options属性值的动态绑定,handelCloseCustomEvent方法处理了自定义事件onClose交互逻辑。

  1. 加载options对应的属性编辑器,对应表单设计器右侧的SettingPanel面板,具体代码参见extension-loader.js:

  PERegister.registerCPEditor('title', 'alert-title-editor',
      PEFactory.createInputTextEditor('title', 'extension.setting.alertTitle'))  let typeOptions = [    {label: 'success', value: 'success'},    {label: 'warning', value: 'warning'},    {label: 'info', value: 'info'},    {label: 'error', value: 'error'},  ]
  PERegister.registerCPEditor('type', 'alert-type-editor',
      PEFactory.createSelectEditor('type', 'extension.setting.alertType',          {optionItems: typeOptions}))

  PERegister.registerCPEditor('description', 'alert-description-editor',
      PEFactory.createInputTextEditor('description', 'extension.setting.description'))

  PERegister.registerCPEditor('closable', 'alert-closable-editor',
      PEFactory.createBooleanEditor('closable', 'extension.setting.closable'))

  PERegister.registerCPEditor('closeText', 'alert-closeText-editor',
      PEFactory.createInputTextEditor('closeText', 'extension.setting.closeText'))

  PERegister.registerCPEditor('center', 'alert-center-editor',
      PEFactory.createBooleanEditor('center', 'extension.setting.center'))

  PERegister.registerCPEditor('showIcon', 'alert-showIcon-editor',
      PEFactory.createBooleanEditor('showIcon', 'extension.setting.showIcon'))  let effectOptions = [    {label: 'light', value: 'light'},    {label: 'dark', value: 'dark'},  ]
  PERegister.registerCPEditor('effect', 'alert-effect-editor',
      PEFactory.createRadioButtonGroupEditor('effect', 'extension.setting.effect',          {optionItems: effectOptions}))

  PERegister.registerEPEditor('onClose', 'alert-onClose-editor',
      PEFactory.createEventHandlerEditor('onClose', []))

上述代码了共加载了9个属性编辑器,其中包含onClose事件编辑器,其他属性使用预先加载的默认属性编辑器。以上使用到的字符串资源分别位于src\lang\zh-CN_extension.js、src\lang\en-US_extension.js两个文件中。

  1. 字段组件开发完毕,扩展组件的加载由extension-loader.js的loadExtension()方法执行,该方法在main.js中被调用。


SFC代码生成


如果你最终使用VFormRender渲染表单JSON,则此部分内容完全可以跳过,无须实现该功能。

1.编写容器组件SFC生成器方法

实现思路很简单,根据容器的JSON配置生成对应的Element UI组件模板代码,打开src\extension\samples\extension-sfc-generator.js,可看到card容器的SFC生成器方法如下:

export const cardTemplateGenerator = function (cw, formConfig) {  const wop = cw.options  const headerAttr = `header="${wop.label}"`  const classAttr = buildClassAttr(cw)  const styleAttr = !!wop.cardWidth ? `style="{width: ${wop.cardWidth} !important}"` : ''  const shadowAttr = `shadow="${wop.shadow}"`  const vShowAttr = !!wop.hidden ? `v-show="false"` : ''  const cardTemplate =`<div class="card-container"
  <el-card ${headerAttr} ${classAttr} ${styleAttr} ${shadowAttr} ${vShowAttr}    ${
      cw.widgetList.map(wItem = {        if (wItem.category === 'container') {          return buildContainerWidget(wItem, formConfig)        } else {          return buildFieldWidget(wItem, formConfig)        }      }).join('')    }
  </el-card
</div`  return cardTemplate}

SFC代码生成大量使用了ES6的模板字符串功能,极大地简化了代码生成逻辑。

2.编写字段组件SFC生成器方法

打开src\extension\samples\extension-sfc-generator.js,可看到alert组件的SFC生成器方法如下:

export const alertTemplateGenerator = function(fw, formConfig) {  const wop = fw.options  const titleAttr = `title="${wop.title}"`  const typeAttr = `type=${wop.type}`  const descriptionAttr = !!wop.description ? `description="${wop.description}"` : ''  const closableAttr = `:closable="${wop.closable}"`  const closeTextAttr = !!wop.closeText ? `close-text="${wop.closeText}"` : ''  const centerAttr = `:center="${wop.center}"`  const showIconAttr = `:show-icon="${wop.showIcon}"`  const effectAttr = `effect="${wop.effect}"`  const alertTemplate =`<el-alert ${titleAttr} ${typeAttr} ${descriptionAttr} ${closableAttr} ${closeTextAttr} ${centerAttr} 
  ${showIconAttr} ${effectAttr}</el-alert`  return alertTemplate}

实现思路同上,根据组件的JSON配置生成相应的Element UI组件模板代码。

3.注册上述两种代码生成器

在extension-loader.js中注册SFC代码生成器,每个代码生成器都需注册。

// ...registerCWGenerator('card', cardTemplateGenerator)  //注册card容器组件的代码生成器// ...// ...registerFWGenerator('alert', alertTemplateGenerator)  //注册alert组件的代码生成器// ...