个人理解动态表单为根据后端数据需求,在前端用不同组件进行展示然后返回表单数据并提交的过程。上图:

图中项目为侧边弹窗,标题为输入框故障类型和优先级为输入框,内容为textarea,大致可以归纳为表单由输入框、文本域、选择框、侧边栏、文件上传、时间选择器等组件组成。

于是跟后端约定速成表单模板格式(以下为部分结果):

[{"id": 0,"pid": 0,"sort": 0,"title": "创建时间","name": "datetime-picker","type": "datetime","placeholder": "","field": "create_at","value": "","format": "","data": [],"action": [],"isRequire": false,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": false,"flag": "","tip": "","options": [],"group": 1
}, {"id": 1,"pid": 0,"sort": 1,"title": "所属项目","name": "ep-selector","type": "","placeholder": "请选择项目","field": "project","value": {"id": "","name": "","address": ""},"format": "","data": [],"action": {"type": "admin","method": "admin.pm.lists","params": {"keyword": "project_name","default": {"project_ids": "all"}},"permissions_key": "add_order"},"isRequire": true,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": true,"flag": "","tip": "请选择项目","options": {"id": "project_id","name": "project_name","address": "address_detail"},"group": 1
}, {"id": 2,"pid": 0,"sort": 2,"title": "工单标题","name": "input","type": "input","placeholder": "请输入工单标题","field": "title","value": "","format": "","data": [],"action": [],"isRequire": true,"regexp": "^[\\u4e00-\\u9fa5-_a-zA-Z0-9\\(\\)\\(\\)]{1,50}$","isDisabled": false,"isReadonly": false,"isShow": true,"flag": "","tip": "请输入有效工单标题","options": [],"group": 1
}, {"id": 4,"pid": 3,"sort": 4,"title": "工单类型","name": "picker","type": "","placeholder": "请选择工单类型","field": "kind2","value": "","format": "","data": [],"action": [],"isRequire": false,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": false,"flag": "level2","tip": "请选择工单类型","options": [],"group": 1
}, {"id": 5,"pid": 3,"sort": 5,"title": "故障类型","name": "picker","type": "","placeholder": "请选择故障类型","field": "kind3","value": "","format": "","data": [],"action": [],"isRequire": true,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": true,"flag": "level3","tip": "请选择故障类型","options": [],"group": 1
}, {"id": 6,"pid": 0,"sort": 6,"title": "优先级","name": "picker","type": "","placeholder": "请选择优先级","field": "priority","value": "614","format": "","data": [],"action": {"type": "qx","method": "qx.tag.lists","params": {"module_id": 32},"permissions_key": "add_order"},"isRequire": true,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": true,"flag": "tags","tip": "请选择优先级","options": {"id": "tag_id","name": "tag_name"},"group": 1
}, {"id": 7,"pid": 0,"sort": 7,"title": "服务时间","name": "datetime-range","type": "datetime","placeholder": ["请选择开始时间", "请选择结束时间"],"field": "service_time","value": ["2021\/02\/23 11:26", "2021\/03\/02 11:26"],"format": "YYYY-MM-DD hh:mm","data": [],"action": [],"isRequire": false,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": false,"flag": "","tip": "请选择服务时间","options": [],"group": 2
}, {"id": 9,"pid": 0,"sort": 9,"title": "服务师傅","name": "input","type": "input","placeholder": "请输入服务师傅名称","field": "service_repairman","value": "","format": "","data": [],"action": [],"isRequire": false,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": false,"flag": "","tip": "请输入服务师傅名称","options": [],"group": 2
}, {"id": 10,"pid": 0,"sort": 10,"title": "工单内容","name": "input","type": "textarea","placeholder": "请输入工单内容","field": "content","value": "","format": "","data": [],"action": [],"isRequire": true,"regexp": "","isDisabled": false,"isReadonly": false,"isShow": true,"flag": "","tip": "请输入工单内容","options": [],"group": 1
}]

id: 字段ID,

pid: 父级关联ID,用户级联

sort: 排序

title: 组件label

name: 组件名称

type: 组件类型

placeholder: 组件说明

field: 组件字段,后端需要

value: 初始化值

format: 组件显示格式

data: 组件初始化数据

action: 需要请求后端数据的组件,里面为请求接口、权限、初始化参数等

isRequire: 是否为必填项

regexp: 组件值正则校验

isDisabled: 是否禁用

isReadonly: 是否只读

isShow: 是否在页面显示

flag: 特殊组件标识

tip: 校验后提示

options: 公共组件不同接口的字段键值对,例如:{key: 'project_id' | 其他键, name: 'project_name' | 其他键,value: 'project_id' | 其他键}

group: 分组

有了表单模板字段相关属性,就需要跟表单数据和组件相结合(以下为部分转换代码)组件可以使用组件库(文章中采用vant-weapp,部分进行二次封装),也可采用小程序原生组件:

//data部分,需要进行后端提交
formData: {multipart: {}, //动态表单部分... //其他非动态表单部分
},//数据转换部分,并完成字段与初始化值对应
let templateArr = res.content; //动态表单模板
templateArr = templateArr.filter(item => item.isShow);
templateArr.map(item => {let _field = `formData.multipart.${item.field}`;this.setData({[_field]: item.value})})this.setData({templateArr})
<view class="{{ item.type === 'textarea' ? 'form-item-mutiline' : 'form-item' }}" wx:for="{{templateArr}}" wx:key="id" wx:for-item="item" wx:for-index="item.id"><view class="form-item-label"><view class="form-item-required" wx:if="{{ item.isRequire }}">*</view>{{ item.title + ':' }}</view><view class="form-item-content" wx:if="{{ item.name === 'input' && item.type == 'text'}}"><van-field data-field="{{ item.field }}" value="{{ formData.multipart[item.field] }}" type="text" border="{{ false }}" label="" placeholder="{{ item.placeholder }}" input-align="left" bind:input="setField"></van-field></view><view class="form-item-content" wx:if="{{ item.name === 'input' && item.type === 'textarea'}}"><view class="textarea-content" hidden="{{ popSelectorShow || audienceShow ||  performerShow || referenceShow}}"><van-field data-field="{{ item.field }}" value="{{ formData.multipart[item.field] }}" type="textarea" border="{{ false }}" label="" placeholder="{{ item.placeholder }}" autosize="{{ textareaOption }}" input-align="left" maxlength="1000" show-word-limit="{{ true }}" bind:input="setField"></van-field></view><view class="file-container"><UploadImg id="imgUploader" maxNum='5' disabled="{{false}}" bind:listChange="imgChange"></UploadImg><view class="upload-tip" wx:if="{{ imgList.length === 0 }}">添加照片(最多可以添加5张哦)</view></view></view><view class="form-item-content" wx:if="{{ item.name === 'input' && item.type !== 'text' && item.type !== 'textarea' }}"><van-field data-field="{{ item.field }}" value="{{ formData.multipart[item.field] }}" type="{{ item.type }}" border="{{ false }}" label="" placeholder="{{ item.placeholder }}" input-align="left" bind:input="setField"></van-field></view><view class="form-item-content" wx:if="{{ item.name === 'ep-selector'}}"><pop-selector data-field="{{ item.field }}" initData="{{ formData.multipart[item.field] }}" placeholder="{{ item.placeholder }}" action="{{ item.action }}" options="{{ item.options }}" bind:setProject="setField" bind:showPop="showPopSelector"></pop-selector></view><view class="form-item-content" wx:if="{{ item.name === 'picker' }}"><pop-picker data-field="{{ item.field }}" initData="{{ formData.multipart[item.field] }}" placeholder="{{ item.placeholder }}" action="{{ item.action }}" options="{{ item.options }}" kind="{{ formData.kind }}" flag="{{ item.flag }}" type_name="{{ item.title }}" bind:setValue="setField"></pop-picker></view><view class="form-item-content" wx:if="{{ item.name === 'datetime-picker' }}"><pop-datetime-picker title="{{ item.title }}" data-field="{{ item.field }}" initData="{{ formData.multipart[item.field] }}" placeholder="{{ item.placeholder }}" bind:setValue="setField"></pop-datetime-picker></view><view class="form-item-content" wx:if="{{ item.name === 'datetime-range' }}"><time-range data-field="{{ item.field }}" initData="{{ formData.multipart[item.field] }}" placeholder="{{ item.placeholder }}" bind:setValue="setField"></time-range></view></view>

由于小程序无法像react(高阶组件),vue(component-is)进行渲染,这里采用wx:if 将组件分类进行渲染,这里没有双向绑定,采用data-field 及没有组件暴露setField 来进行数据赋值绑定,这里需要注意textare遇到弹窗时placeholder和正文会浮动偏移,可以采用显示隐藏方式处理,也可用cover-view进行处理,视实际情况而定。

数据及表单选择完成后,提交前需要进行校验:

for (let i in templateArr) {let item = templateArr[i];let field = multipart[item.field];if (item.isRequire) {if (item.regexp && field && !new RegExp(item.regexp).test(field)) {Notify({type: 'danger',message: item.tip});flag = false;break;} else if (!field && typeof field !== 'object') {Notify({type: 'danger',message: item.tip});flag = false;break;} else if (typeof field === 'object' && !Array.isArray(field) && !Array.from(new Set(Object.values(field)))[0]) {Notify({type: 'danger',message: item.tip});flag = false;break;} else if (Array.isArray(field) && item.name === 'datetime-range' && field.length === 2 && new Date(field[1]).getTime() < new Date(field[0]).getTime()) {Notify({type: 'danger',message: '结束时间必须大于开始时间'});flag = false;break;} else {flag = true;}} else {if (item.regexp && field && !new RegExp(item.regexp).test(field)) {Notify({type: 'danger',message: item.tip});flag = false;break;} else if (Array.isArray(field) && item.name === 'datetime-range' && field.length === 2 && new Date(field[1]).getTime() < new Date(field[0]).getTime()) {Notify({type: 'danger',message: '结束时间必须大于开始时间'});flag = false;break;} else {flag = true;}}}return flag;

最后,提交完成!!!

记微信小程序动态表单实现相关推荐

  1. 微信小程序常用表单组件

    微信小程序常用表单组件 1.常用表单组件 1.1 button 1.2 checkbox 1.3 input 1.4 label 1.5 form 1.6 radio 1.7 slider 1.8 s ...

  2. 微信小程序插件---表单验证篇

    微信小程序插件---表单验证篇 项目下载地址 WxValidate - 表单验证 插件介绍 该插件是参考 jQuery Validate 封装的,为小程序表单提供了一套常用的验证规则,包括手机号码.电 ...

  3. 微信小程序 form表单验证

    业务需求:微信小程序提交表单的时候必填的项要提示,还要电话要校验 首页,先搞一个校验的公共方法 validate.js /*** 表单验证* * @param {Object} rules 验证字段的 ...

  4. 【微信小程序】表单提交验证及获取表单输入的值

    效果图: 说明:请选择房屋所在城市的效果是省市区选择器,刚开始我们可能直接在picker选择器中直接包含一个input输入框实现,但是这样的话点击选择的话可能聚焦在输入框中,我们想要的效果是点击的时候 ...

  5. 【微信小程序】表单验证提交

    效果图: 说明:点击一键预约提交表单时我们需要验证一些必填项以及它们的格式.微信小程序表单验证跟vue的input双向绑定不同,微信小程序只能通过button按钮提交form表单,然后通过监听表单提交 ...

  6. [微信小程序]提交表单返回成功后自动清空表单的值

    微信小程序开发交流qq群   173683895    承接微信小程序开发.扫码加微信. 正文: 实现思路: 给每一个input绑定相同的value对象,提交成功后把这个对象赋值为空.  下面看代码: ...

  7. 微信小程序-提交表单成功弹窗提示

    微信小程序中toast消息提示框只有两种显示的效果,就是成功和加载,使用wx.showToast() 效果如下 相关参数如下 代码很简单 wxml: <button type="pri ...

  8. wps表单小程序 服务器错误,微信小程序WPS表单怎么在钉钉使用

    微信小程序不支持 table 标签,在网上找到一个使用 flex 来实现表格的简明例子,记录一下. table.wxml head1 head2 head3 {{item.code}} {{item. ...

  9. 微信小程序Form表单提交按钮获取不到表单数据

    问题描述:再写微信小程序的一个案例时,bindsubmit绑定事件后,事件对象e.detail.value中的值是个空对象!!! 代码实现: // index.wxml <form action ...

  10. 小程序提交表单mysql_微信小程序form表单提交到MYSQL实例(PHP)

    小程序相对于之前的WEB+PHP建站来说,个人理解为只是将web放到了微信端,用小程序固定的格式前前端进行布局.事件触发和数据的输送和读取,服务器端可以用任何后端语言写,但是所有的数据都要以JSON的 ...

最新文章

  1. pytorch实现手写数字识别_Paddle和Pytorch实现MNIST手写数字集识别对比
  2. python matplot 绘图
  3. odu oracle 价格_Oracle数据库ODU的几种恢复场景
  4. java jndi 例子_MEJB附录B,jndi例子无法运行的问题
  5. 汇编语言AND指令:对两个操作数进行逻辑(按位)与操作
  6. [Prism]Composite Application Guidance for WPF(10)——系列目录导航
  7. 对将‘47 ’转化为int格式错误的问题解决
  8. office2010删除分页符
  9. 【php】 自带的过滤机制
  10. [转载]程序员如何写出杀手级简历
  11. 95-38-025-Buffer-Buffer1
  12. 基于DevExpress XtraGrid控件实现的凭证式显示
  13. strace动态调试 php,strace调试
  14. 【优化求解】基于蝙蝠算法求解最优目标matlab源码
  15. vue开发app项目实例
  16. 量子计算机物理学,使用量子计算机来测试物理学的基本原理
  17. 罗永浩的带货直播你看了吗?
  18. 37、T5L迪文屏C51开发之绘制2D形状
  19. 概率论-1.4 条件概率(重点:对P(A | B)、P(AB)、P(B)之间关系的理解)
  20. openmediavault安装

热门文章

  1. 15个令iPhone用户嫉妒的Android widgets 桌面组件
  2. orocos安装_动脑共享单车环境搭建
  3. 新一线城市竞争力盘点,用Python绘制动态图带你看懂!
  4. 建立了一个博客园创业者QQ群
  5. java mp3合并_java合并MP3文件
  6. Centos7安装Mysql、九条命令搞定
  7. 在 word 中加入 Mathtype 公式编辑器 解决办法
  8. python-opencv尺寸测量
  9. 一个安全删除文件的shell命令
  10. vbox虚拟机添加硬盘