? 这是第 58篇不掺水的原创,想要了解更多,请戳上方蓝色字体:政采云前端团队关注我们吧~

本文首发于政采云前端团队博客:ZooTeam 拍了拍你,来看看如何设计动态化表单

https://www.zoo.team/article/dynamic-form

前言

对于 ToB 业务而言,随着业务的不断壮大,接入的客户逐渐增加,相同页面的差异化的需求越来越多,尤其是在表单层面,小到多一个字段少一个字段这种简单的需求,大到整个页面不变的只剩下一些基础字段。一旦这种差异化需求随着业务量的增长而膨胀起来。代码中的 IF ELSE 越来越多,项目就越来越难以维护。基于这个问题,比较普遍的解决方案要么是项目拆分,要么相同项目的代码分割。

这两种方案都有维护成本比较大的弊端,那么有没有更好点的解决方案呢。本文就带你了解一下动态化表单搭建。

什么是动态表单

先下个定义,动态表单是页面根据管理端配置的不同的 Schema 结构,动态渲染出不同的表单项的表单。动态表单一般分两个部分,管理端和渲染端。管理端配置表单项及相应的简单交互产出 Schema 数据。渲染端根据 Schema 数据相应的渲染出不同的表单项并实现简单的交互。大致流程如下。

图片

动态表单的实现

表单配置

对于 Schema 数据的配置,考虑到接入业务方的接入成本及维护成本。管理端采用了可拖拽式的所见即所得配置面板。这里共分为四个部分,备选组件面板,拖拽面板,组件属性面板和表单属性配置(视图属性)。具体实现如下图:

图片

备选组件面板

左侧备选组件栏里的备选组件共分三种,容器组件,基础组件,自定义组件。

  • 容器组件——是用来存放基础组件的组件。例如表单组件,子表单组件,表格表单组件。这些组件都是内部可以存放其他子组件的组件。属于容器组件。系统内置了 3 个容器组件,对于中台系统而言,容器组件不会太多样化。所以容器组件没有做自定义组件的功能。当然后期如果需要的话也可以扩展出容器组件的自定义组件功能

  • 基础组件——就是普通的表单项。系统内置了 13 个基础组件。这些组件都是基于 Antd 的 React 组件做的二次包装

  • 自定义组件——业务方经常出现一些个性化的表单项,例如某个输入框后面加个链接跳转之类的需求,对于这种组件,系统提供了自定义组件的注册及配置功能。这样业务方就可以自由的维护专属于自己的业务表单组件了。同时也解放出表单系统维护者的时间。组件注册同时也是一个更加轻量级的自定义组件模块。因为不同的组件需要设置不同的参数,所以该组件对应的右侧属性表单也应该是不同。这部分下文组件属性部分会详细说明

拖拽面板

拖拽面板就是维护组件展示关系的面板,同时提供拖拽排序、删除、复制、预览等功能。

具体实现方案采用的是 React-DnD。

组件配置

属性配置面板本身就是个更加轻量级的动态表单实现。只是 Schema 由开发者直接写死而没有一个可配置的页面而已(自定义组件注册部分例外)。当在拖拽面板选中一个组件时,组件属性配置面板会渲染出相应组件的可配置项表单, 这里提供一下简单的组件属性配置面板的 Schema 供大家参考。

[{  label: '是否可见',  code: 'visible',  widget: 'switchBtn',  initialValue: true},{  label: '是否可编辑', // 标签文案  code: 'code', // 字段编码  widget: 'switchBtn', // 组件类型  initialValue: true, // 初始值 默认可编辑  hide: 'exp: visible === false', // 是否隐藏  required: true // 是否必填}]

细心的同学会发现 hide 字段写了个表达式。这里通过 exp: 开头作为一个表达式的标识。表达式的可以使用的变量是属性表单内的值。

比如上面这个例子,visible 是上面定义了一个是否可见的字段。如果当前选中的这个组件不可见的话,是否可编辑本身就无从谈起,所以直接隐藏掉。

容器属性 共有的属性有标题、编码、是否可见、以及容器结构是否对数据透明。

前面三个好理解。容器结构是否对数据透明是什么呢?前面说过,我们的容器组件是可多层嵌套的,那问题来了,数据咋办,表单嵌套会导致数据也跟着嵌套。所以这里参考了阿里的 Formily 开源表单方案。使用一个 skip ,来使其对数据透明。即:

{  "title": "表单",  "type": "form",  "fields": [{    "name": "name",    "label": "姓名"  }, {    "title": "子表单",    "skip": true, // 表单结构对数据透明    "name": "item",    "type": "form",    "fields": [      {        "name": "object",        "label": "物品"      }, {        "name": "brand",        "label": "品牌"      }    ]  }]}

skip 为 false 时返回的数据为:

{  "name": "简名",  "item": {    "object": "电脑",    "brand": "Mac"  }}

skip 为 true 时返回的数据为:

{  "name": "简名",  "object": "电脑",  "brand": "Mac"}

组件属性 分为基本属性和组件属性,基本属性是所有属性共有的。标题,编码,是否可见,是否必填等属性都是基本属性。组件属性则是组件私有的属性。

比如 Select 组件会需要一个数据来源,以及该组件是否多选之类的。基本属性直接写死。组件私有属性则通过远程数据库维护。自定义组件的注册就需要涉及到这部分的数据管理。自定义组件的注册表单如下:

图片

其中组件可配置属性就是组件私有的属性的定义,注册时定义,配置该组件时赋值,渲染端渲染时应用。可配置属性还需要支持表达式的填写。比如某个组件需要远程数据,url 提供了,但是参数需要取当前时间,这个时候就需要组件属性支持表达式的解析或者少量代码读写运行了。这些属性除了组件自定义属性以外,还有组件默认值,组件自定义校验,组件 onChange 事件。以自定义校验为例:

图片

表单属性配置(视图属性)

这部分在上图中没有显示,是在组件属性右侧。表单属性分两部分,交互规则和接口绑定。

图片

交互规则 表单交互规则在表单级别绑定,而不是在字段级别。进行就近配置的目的,是为了方便管理,进入一个表单配置,该表单的交互在右侧一目了然。

接口绑定 则是表单渲染过程中有可能涉及到一些远程数据的读取,比如默认值等。这部分数据的配置需要用到远程数据。表单上绑定了接口之后,表单初始化之前先发请求获取绑定接口的数据,相应的表单组件里就可以使用到该数据进行初始化。

管理端数据流转

管理端的功能是构建出一个目标 Schema。每个备选组件都有基本信息和相应的组件可配置属性信息。组件基本信息主要用于组件面板展现。组件可配置属性需要在右侧属性配置时渲染成一个表单给使用者去配置,故而组件可配置信息又是一个简化版的 Schema,这里称为组件级 Schema。在拖拽页面中添加一个组件,通过解析组件的组件级 Schema 及组件放置位置给目标 Schema 添加一个组件数据。然后在拖拽页面中选中该组件,右侧属性配置会相应渲染出组件级 Schema 所描述的表单给用户配置填写。用户配置时直接修改目标 Schema 中相应选中组件的信息。数据流转图大致如下:

图片

表单动态渲染

因为表单页面还会有各种定制化的需求,表单渲染端这里采用组件的形式,提供了两个组件,一个组件作为表单页面的外层包裹组件主要功能是发请求获取相应的 schema.json 数据。另一个组件就是通过上层组件的数据渲染相应的表单。示例:

import { FormPageWrap, MainForm } from './index';@FormPageWrap({  prefix: '/api/budget', // 业务方接口前缀  getFormParams: (props) => { // 获取表单结构参数    return {};  },  getDataParams: (props) => { // 获取表单回填数据参数    return {};  }})export default class FormPage extends Component {  render() {    return (      <div>        // 表单各种额外显示内容<MainForm // 表单渲染组件customComponent={{            test: TestComp,          }}extraParams={{}}        />        // 表单各种额外显示内容div>    );  }}

内部实现则是根据 Schema 渲染相应的组件。

待完善

目前系统部分功能还有待完善。具体有几点:

  • 自定义组件的异步加载。当一个表单需要新增加一个自定义组件时,项目需要重新构建发版。如果自定义组件可以单独发布,就可以做到及时添加一个自定义组件,不需要项目重新构建发布了。当然如果自定义组件太多,异步加载还是会有些性能问题。而这就需要做到同页面下多组件代码合并了

  • 一些配置的沉淀复用。比如某些经常配置的表单块。可以沉淀为常用组件。直接选择使用,可进一步简化配置流程

  • 同页面下的一些相同区块,如果每个页面都单独维护,会极大的增加维护成本、抽取并联动,可以极大的减少维护表单的成本

展望

对于动态化表单的能力远不止目前看到的动态表单搭建:

  • 对于管理端流转出来的 Schema 数据可以进行二次加工,从而实现对于用户的权限,业务配置等能力的扩展

  • 管理端配置出来的 Schema 不止可以用在动态表单渲染中,还可以作为数据模型去描述一个静态数据的结构。从而提供各业务系统配置数据的构建能力

  • 前端渲染组件也不一定要和管理端的 Schema 完全耦合在一起。单独拿来使用也是完全没问题的,这样对于某些简化版动态表单的能力也能做到支持

看完两件事

如果你觉得这篇内容对你挺有启发,我想邀请你帮我两件小事

1.点个「在看」,让更多人也能看到这篇内容(点了「在看」,bug -1 ?)

2.关注公众号「政采云前端团队」,持续为你推送精选好文

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

antd 动态添加表单_ZooTeam 拍了拍你,来看看如何设计动态化表单相关推荐

  1. antd 动态添加表单_react Ant Design 动态生成表单,并带验证

    写点杂记,写这个文章原因是因为我对象要做这个功能,我们正好用到了特意拆写成了1个简单的demo import React, {Component} from 'react' import {conne ...

  2. mysql栏目表设计_MySQL表设计

    文章摘自: https://mp.weixin.qq.com/s?__biz=MzI2NDU3OTg5Nw==&mid=2247483799&idx=1&sn=4d1f45ab ...

  3. 交叉表 列字段排序_百度App设计部:四步打造交互设计自查表

    UXD设计研究室 · 百度MEUX外部合作自媒体 设计自查是设计师常用的检验工具,经常以"自查表"形式呈现,可以帮助我们快速遍历设计方案,修正遗漏或不周.善用设计自查,不止可以避免 ...

  4. html表单中动态添加下拉框,antd Select下拉菜单动态添加option里的内容操作

    antd Select下拉菜单动态添加option里的内容,通过form表单绑定select选中的值 提供一个公共的方法,每次只需去调用这个方法就行了 //这里是示例数据格式 let giftScop ...

  5. html实现动态多表单输入,提交多个动态添加的html表单

    我正在构建一个可以动态添加表单的功能.不是表单字段,而是一个完整的单独的HTML表单.提交多个动态添加的html表单 我使用JS添加它们. add_email_template $('#add_ema ...

  6. form表单 无法提交js动态添加的表单元素问题。。

    第一种情况, 这种情况js动态添加的表单元素是不能提交到服务器端的 <table> <form method="post" action=" url   ...

  7. layui 表单动态添加、删除input框

    html部分 <div class="layui-form-item" ><label class="layui-form-label"> ...

  8. element实现form表单动态添加email效果

    前言: vue中使用element实现form表单动态添加email效果 效果: 实现步骤: 实现源代码: <template><div><el-form ref=&qu ...

  9. vue实现动态添加表单

    前言 日常开发中,动态添加表单的场景还是蛮多的,可能第一次听到动态添加表单的同学会有一点懵,但其实实现起来还是很简单的,下面一起来看看吧. 实现思路 当我们点击 "新增车辆信息" ...

最新文章

  1. [NOIP 2015]运输计划-[树上差分+二分答案]-解题报告
  2. D - Connect the Cities (HDU - 3371)
  3. Linux高性能网络:协程系列08-协程实现之调度器
  4. java项目遇到的问题_java系列:项目中遇到的一些问题(持续更新中)
  5. dp打开思路:HDU1029 HDU1087 HDU1176 HDU1257 POJ1458(水题不水)
  6. v-bind:href= 拼接字符串 - 代码篇
  7. P60 ---AI 在P60 上的人应用
  8. 特斯拉第四季度生产超30.5万台车 全年交付近百万台
  9. C# 调用Dll中非托管C++代码时,函数参数的类型对照
  10. jsonrpc php使用,基于php的json rpc原理及应用
  11. 2020电信宽带费用_现在电信宽带多少钱一年,2020年电信宽带套餐价格表
  12. Linux 程序性能分析与优化
  13. 联想E43升级bios激活windows 7
  14. 分享几个好用的易语言编程助手
  15. 我与我的专业计算机网络作文,我与网络的故事作文600字
  16. php lararel,Voyager 的使用及二次开发
  17. Cocos Creator 调试入门
  18. 【Vegas2010】1月24日-钢琴教材从零起步的进阶选取
  19. xbox win10测试软件,xbox one在win 10 系统怎么测验
  20. python安装csv出错,用Python编写csv时出错

热门文章

  1. android post json格式,Android中post请求传递json数据给服务端的实例
  2. mysql主从切换机制torch_Mysql主从复制 - osc_y0vjyklt的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. 加载cv2调用摄像头_用Python获取摄像头并实时控制人脸
  4. linux启动weblogic指令,linux下如何启动和关闭weblogic
  5. linux之find命令详解
  6. flask_sqlalchemy连接Mysql报TypeError: create_engine() got an unexpected keyword argument 'encoding'解决办法
  7. shell 连续空格输出
  8. mov word [LABEL_DESC_CODE32 + 2], ax
  9. matlab中antoine方程应用,五参数antoine方程
  10. java qq音乐接口 api,QQ音乐解析API接口更新:支持HQ,ape,flac无损音质,缓存功能