背景
Form是前端开发中使用频率最高的元素之一,也是变化最复杂的组件之一。
Form虽然从结果上看,是表单内容的填写+验证+提交,但在此过程中还是有很多变化的。例如表单内容之间的联动,非常规表单内容的组合展示,复杂验证等等。
如何更快速的完成一个Form的编码是前端工程师不断关注和努力的方向之一。
最近工作中遇到一个较为复杂的Form,输入项有六七十个,联动极多。Form中还穿插着表格等其他组件的展示。
对如何写好这个form,做了一些思考,列在本文中。
调研
常见的几种方式:
- Form内容的叠加
- 描述:这种方式最简单直接,把所有的输入项平铺在Form中,所见即所得。
- 优点:便于调试,逻辑相对简单,无学习成本
- 缺点:缺少封装,缺少拆分,不利于扩展。如果是大型Form,一个文件过大,而拆分又会增加非常大的复杂度
- JSON-SCHEME
- 描述:充分利用了Form键值对的本质,把所有Form内容抽象为一个JSON的数据,通过JSON动态渲染Form
- 优点:封装性好,修改简单,便于扩展
- 缺点:得到的JSON配置文件会很大,增加了阅读难度,不利于调试,有学习成本
- 可视化搭建
- 描述:这可能是比较高级的方案,利用Form组件的常规性,把常用的输入项封装为物料,直接拖拽生成Form。
- 优点:构建UI上应该是最快速的,而且修改也很简单。甚至可以把这一搭建工作交给产品或设计。
- 缺点:平台需要提前搭好和维护,且只适合于内部逻辑不复杂的Form。一旦逻辑变得复杂,后续开发成本变得更高。
没有哪种方案是最好的,只有更合适的。
针对我目前的项目,很巧合,从需求1.1到1.3都有一个Form的开发,1.1采用的是第一种叠加方式,1.2采用的是第二种SCHEME的方式。我目前在做的是1.3的需求。
由于1.3的Form更加复杂,在参考了上面2种开发方式后,最终采取了比较折衷的方案。
整体思路
原型-> 基础配置文件 -> 扩充配置文件,完成逻辑开发
从原型生成基础配置
看一眼原型,写一部分代码的方式很繁琐,而且特别低效。来回切换搞得开发思路短路,而且眼疼。
但偏偏Form的性质又是最适合这种方式的,每一个字段的名称,描述,验证,备注都需要一点点的搬运。
所以根据原型,先写一个config,后续的开发工作就变成了基于config文件的逻辑开发。
举个例子:
比如上面这个简易的Form模型,我们根据模型可以得到这样一个config内容。
默认所有显示出来的字段都是必填的。
|
|
字段说明
- key: 适用于循环的唯一key值。
- formKey: 在form中的key,可以是提交给后端的字段名。一个formKey可能对应多个key值,对应一个formKey的多种展示方式,但出于显示状态的只能是一个。
- label:输入项标签。
- labelWidth:输入项标签的宽度。
- span:输入项组件的宽度。
- hide:是否显示,目前定义的是function,也可以支持其它类型。
- mode:展示模式,比如 edit/disabled/view。定义多种模式,便于切换编辑和查看。目前定义的是function,也可以支持其它类型
- rules:正则规则
- render:function,输出为要展示的内容。
其它:
- config中假设已经定义了一个getCurrentValueByKey的函数,表示从当前的form或defaultData中获取某个formKey的值。这个函数需要自己后面补充。
- render中定义了函数的输入是一个object,包含的内容是 parentForm,mode,defaultData
- parentForm:当前form中的值
- mode:目前的展示模式,可以根据这个值渲染不同内容
- defaultData:form的默认值
- 定义了一个常量FULL_WIDTH,对展示宽度做定义
得到上面的config后,后续的开发就可以脱离原型了。
扩充config
有了上面的config,剩下待做事项还有:
- 循环渲染。
- 每一个输入项的render中的组件,onchange的时候需要赋值给整个form,方便其他输入项使用
一个Form的简单模型如下:
说明:
- 实际代码中使用的不是原生的form标签,而是一个封装的Form组件。Form中对FormItem组件中的onChange事件进行了统一的监听,然后添加了onSubmit/onReset/onValidation等一些钩子函数,可以做一些统一处理。
- FormItem里面做了对样式的处理,还有validation验证失败时的一些统一处理,展示。
Demo
后续会补充一个简单完整的Demo上来。
问题
- form输入项很多时,config会非常大,需要拆分
- Form和FormItem组件还可以做更多事情,以便减少config中的内容