背景
对团队的中后台项目进行场景统计后,我们发现:查询列表、新建编辑页,在其中占有绝对的数量比例,所以表单场景自然成为了开发提效的重点方向。
随着中后台业务的发展:
-
项目的可维护性变差。
主要是项目中会出现一些维护困难的”巨石表单”。虽然数量不多,但是一旦评估不慎,很容易造成开发 delay。导致的原因一方面是由于其承载的业务逻辑本身就足够复杂,另一方面也是由于缺乏统一的开发规范约束、开发人员频繁变动,导致欠下了技术债。并且,如果完全依靠因果关系,从规范强约束、维护人员稳定这两方面着手去解决这个问题,显然并不现实。 -
存在重复的工作量。
中后台很多页面都长的很相似,比如一些常规的查询列表页。复制粘贴的过程中,开发人员常常不会收获任何技术热情与成就感,所以希望宝贵的精力还是放在更有进步与挑战的事情上。 -
需求实现越来越依赖远程动态渲染能力。
最常见的就是需要根据登陆人的身份角色,下发不同的字段。并且,在一部分需求中,后台虽然只涉及极少量的字段改动,但也需要随其他端开启漫长的”陪跑上线”。
想要解决这些问题,这就需要引入更清晰的表单描述以及远程动态渲染等核心能力,所以,就想尝试能否换一种开发思路,借助 JSON-schema 强大的表达能力,解决我们的项目中的痛点。
领域语言:
表单场景作为前端开发中一块非常经典的领域,发展到今天,也形成了一套专属的领域语言。同时为了后续阅读、交流的效率,也需要统一下对表单技术的名词解释。
-
JSON-Schema: 狭义上是指满足标准 JSON-Schema 规范的一份表单字段描述协议。但这份规范是一份纯字段的表述,在真实的业务场景中往往需要 UI 布局、校验、联动等额外的表达,所以广义上的JSON-Schema 也可以指在大致的规范基础上进行个性化扩展后的最终渲染协议。
-
动态语法表达式: 联动、校验等表单功能都涉及逻辑计算。在 js 中逻辑的编写要依赖变量、三目运算、函数等,但 JSON 对这些是天然缺失的,为了弥补,大部分支持 JSON-Schema 的表单方案都支持用特定的模版语法字符串来为 JSON-Schema 增强一些逻辑表达能力,类似于
visible:"{{formData.x.y === '1' ? true : false}}"
这样的。 -
表单渲染器(form-render): 根据一份字段描述协议将表单渲染到用户界面上,比如 formily、x-render、react-schema-form 等都是此类。
-
表单编辑器 (form-editor): 又名”表单设计器、可视化表单配置器”。是后台可视化生成 JSON-Schema 的核心组件,负责以友好的拖拽交互方式,最终生成并导出一份渲染协议,驱动前台的表单渲染。
-
远程动态渲染: 简单讲就是上述后台表单编辑器 + 前台渲染器,组合而成的一套技术方案。大致流程是后台拖拽生成 JSON-Schema、前台通过配套的渲染器将它解析渲染出来。
-
联动:
-
主动联动: 通过监听特定字段的变化去主动控制其他字段的状态(常见的状态变化有显隐、值改变、校验规则变化等)
“我发生了 xxx 的变化,需要触发 xxx 进行 xxx 变化”
-
被动联动: 某个字段是否需要发生状态的改变,取决于它依赖字段有没有发生变化。
“我是否需要 xxx,是因为我依赖的 xxx 发生了变化”
-
-
校验:
- 按是否需要调后端业务接口可分为同步或异步校验。
常见误区:
-
引入 JSON-Schema 一定可以提升代码的可维护性?
首先,通过手写 JSON的方式去驱动表单渲染,在代码的可维护性方面相比 jsx,非但没有提升,反而变的更差。主要表现在:
- 代码的复用性变得很低。因为一份 json 配置不像 jsx 一样可以灵活的分隔抽离为一块块的组件进行复用。
- UI 布局处理方面也不如直接写 jsx 灵活。json-shema 的强项在描述数据 model、而非 view。
- 缺少 TS 类型提示。 tsx 开发一个表单可以处处获得 TS 类型提示,一些提前写好的业务枚举在 vscode 中也可以自动提示,非常方便,JSON 显然很难做到。
小结:JSON 天然的更适合机器来识别解析,并不适合前端开发者在页面手动进行维护。这也是formily要提供多种开发模式的原因所在,比如它的MarkupSchema模式更适合前端手写、JSON-Schema模式更适用于远程渲染。所以, 以上问题,那就需要有一个表单编辑器来可视化生成这份 JSON,而非手工编写。
-
JSON-Schema 方案可以大大简化表单开发的复杂度?
答案是并不能。首先要明确一点,表单开发的复杂程度,其根本还是取决于业务逻辑的复杂度。利用一个可视化后台生成 JSON 驱动前台表单渲染,只是功能实现方式变了,由开发人员编写 jsx 代码,转变为开发或运营去可视化操作表单字段的各种选项。往往从工作量上来说,并没有减轻,反而常常因为 JSON 的表达性比不上图灵完备的 js, 显得不够灵活。两者的区别有点类似于写 markdown 和编辑 word 的区别。
JSON-Schema 的核心优势在于动态性及可视化。
- 动态性。避免频繁上线,简单的字段改动,比如去掉一个表单项、增加一个列表展示项等。可以做到一键发布,不需要漫长的编译上线流程。有些业务场景需要跟据当前登陆人身份下发不同的操作字段,联动、校验规则也可能不一样,这就属于强需求了。
- 可视化。 利用 JSON-Schema 强大的表达能力,可以实现后台表单配置化。大大降低开发门槛,不需要学习 react、antd 等技术栈也可以通过简单的操作培训,通过拖拽即可生成一个表单页。
市面开源方案对比
针对我们的需求场景,确定了对表单渲染器的核心诉求:
- 具备远程动态渲染能力。
也就是支持 JSON-Schema ,这是硬性条件,所以 formik、react-final-form、react-hook-form 等一大堆专注于表单领域某一项比如极致性能、对 Hook 支持更好、更先进的数据管理等的表单库就直接排除在我们的选项外了。 - 支持完善的动态逻辑表达能力。 在JSON-Schema层面,能够完善的应对一些联动及动态校验场景。并且最好拥有一些底线思维,比如提供的动态语法一旦不满足要求,可以直接手写字符串的 js function(最好解决作用域的问题)。
- 拥有完善的自定义能力。
一旦内置的组件无法满足需求,可以方便的以自定义组件的方式快速接入。还有自定义校验规则、文案等。 - 拥有一定的 UI 布局表达能力。
- 最好有处理异步数据源的能力。比如一个下拉选项,可选项需要从后端异步拉取,这是非常常见的需求。但如何让一个静态的 JSON 表达异步请求,是一个难点。
市面上主流的支持 JSON-Schema 的开源渲染器主要有:
- formily2 阿里集团共建,是国内开源表单库中影响力最大的一个。定位是专注于解决复杂表单场景下的一些痛点。
- x-render 阿里飞猪旗下的,定位是很易用的中后台「表单 / 表格 / 图表」解决方案。
- Formast 腾讯墨子工作室打造,定位是成为一套通用的动态表单解决方案。
- react-jsonschema-form 国外的一款用于从 JSON-Schema 构建 Web 表单的 React 组件。
x-render | formily2 | Formast | react-jsonschema-form | |
---|---|---|---|---|
动态逻辑表达能力 | 好 | 一般 | 极好 | 差 |
支持自定义组件 | 是 | 是 | 是 | 否 |
支持UI布局能力 | 是 | 是 | 否 | 否 |
异步数据源 | 不支持 | 不支持 | 支持 | 不支持 |
学习成本 | 低 | 高 | 高 | 一般 |
开源氛围 | 一般 | 好 | 差 | 好 |
配套开源的表单编辑器 | 有 | 有 | 无 | 无 |
react-jsonschema-form
因为严重耦合bootstrap的UI框架,所以直接可以忽略了。
formast
的开源氛围及更新频率不是很好,目前整体来看偏内部使用的感觉,但是它强大的动态语法表达式令人印象深刻,并且它是这几款中唯一可以在JSON层面支持一定的异步数据源的表单库。
formily
一路走来,重构过多个版本,目前v1-v2的升级依然存在较大的断层更新,而且上手成本依然很高,对它纠结过很久,但最终还是放弃了。但它的理念我还是非常认同的,专注于解决复杂表单场景,所以创造性的提出了effects、路径系统、reaction等概念,各个击破解决各种表单领域的边界问题,基于JSON-Schema的远程渲染只是它的一项非核心能力,MarkupSchema模式才能够发挥它的最大价值。所以,综合下来,并不太匹配我们的需求。
综合来看,x-render是其中表现最均衡的一款。 虽然在异步数据源、动态逻辑表达等方面并没有优势,但它的自定义组件功能使用起来非常方便,一旦内置功能不满足需求,自定义扩展的成本最低。
总结
x-render
本身附带的有一个开源的表单编辑器。已经集成了物料拖拽等基础交互,所以,整体的表单编辑器可以基于它进行二次开发。渲染器这部分, 我们可以利用它易用的自定义组件能力整体将内置组件封装一层异步逻辑去支持缺失的异步数据源等功能,扩展性会比较强。这个x-render实际应用集合里有一些比较成熟线上例子,这也是选择x-render作为最终方案的重要信心来源。