京东动态表单配置方案DripForm开源啦~

一、简介

DripForm 是由京东零售 iPaaS 团队开源的 React 表单组件,可根据不同的 UI 库进行灵活扩展,包含渲染、校验、可视化编辑等能力,通过配置化解决各类复杂表单场景。

项目仓库:github.com/JDFED/drip-…

二、背景

表单是 CMS 等 B 端业务中出现频率最高的场景,其业务复杂度往往也非常高,不仅要考虑样式布局、数据校验及提交,还需要实现异步逻辑、嵌套联动等功能。同时 B 端业务的生命周期普遍较长,意味着在实际开发时,若一开始没做好规划,代码只会充斥更多的 if elseswitch case 等逻辑,最终导致系统维护成本大幅上涨。

另外,在前端层面外,表单还存在前后端校验能力无法协同等情况。经常发生前后端的校验规则不一致,或是一端漏校验的情况,并且维护两份代码也带来了更高的成本。

因此,我们设计并开源了动态表单配置方案 DripForm 去解决以上问题,提升表单的开发效率。

三、 亮点与差异

相对业内其他方案,DripForm 具备以下亮点:

  • 语义化:简洁高效的 JSON 协议有助于开发者理解。
  • 校验一体化:依托于 ajv 的标准化校验能力,可实现前后端校验一体化。
  • 可视化:可视化搭建表单及修改表单 Schema 。
  • 可扩展:支持二次开发,可扩展自定义组件集、校验集。

基于标准化协议可实现的前后端校验一体化、可扩展能力等都是 DripForm 与其他方案最大的差异,同时可视化和自动化也能进一步减少协议的学习及配置成本。

四、 如何使用

DripForm 可以独立作为 npm 模块使用,也可搭配可视化生成器通过拖拽生成 Schema 。

npm install @jdfed/drip-form @jdfed/drip-form-theme-xxx
复制代码

注意:xxx为主题库的名字。

简单使用

import React, { memo } from 'react'
// 引入核心包和主题
import DripForm from '@jdfed/drip-form'
import dripTheme from '@jdfed/drip-form-theme-xxx'
import '@jdfed/drip-form-theme/dist/index.css'
// 引入配置项
import unitedSchema from './unitedSchema.json'

const Form = memo(() => {
  return
    <DripForm
      unitedSchema={unitedSchema}
      uiComponents={{'drip': dripTheme}}
    />
})
复制代码

除了以上面向编程开发的方式,DripForm 结合 DripDesign 、DripTable 等模块,并配合 iPaaS 内 FaaS 能力,提供了一个可以低代码快速搭建 CMS 的平台 DripWorks 。以上的这些模块、平台也会在后续逐步开源或对外提供体验。

五、 架构设计

DripForm 架构设计的目标是降低团队表单开发的维护成本,以易于使用、灵活扩展的方式解决表单开发中常见的联动、校验、异步获取数据、自定义表单等复杂场景。

1. 功能梳理及设计

核心功能包括 UI、校验、联动,通过 JSON Schema 协议进行配置。除此之外还需具备扩展、可视化等功能。

  • UI:表单的展示与行为。需满足不同业务对不同UI库的诉求,考虑到目前主流ui库都很成熟稳定,因此 DripForm 架构上 UI 库解耦,可通过主题应用不同的 UI库。
  • 校验:复杂表单值的校验。使用 JSON Schema 规范数据校验,配合 ajv 实现前后端校验统一。
  • 联动:表单项变化后,不同表单间的联动关系,采取事件广播等方式实现。
  • 扩展性:通用控件及校验无法满足全部业务诉求,因此 DripForm 还支持自定义组件集、校验集。
  • 可视化:JSON 配置复杂起来不比写代码简单,因此配套提供可视化生成器,以低代码方式进一步提高表单效率,也可作为 npm 独立使用。

2. 主要模块

上述功能,DripForm 主要通过标准化的协议,搭配表单核心、主题、行为校验等模块实现,并额外提供了表单可视化生成器( generator )。

1) 协议规范

DripForm 的协议分内外两部分,对开发者提供精简的 unitedSchema ,内部又分为配置校验的 dataSchema(即 JSON Schema 规范)、配置 UI 的 uiSchema 两种。

DripForm是如何设计,并把dataSchemauiSchema 演进到 unitedSchema 的?可以通过下面这个案例来说明,假设有一份表单数据如下:

{
	name:'张三',
	age: 18
}
复制代码

1、输出对应的 dataSchema 协议:

{
    "type": "object",
    "properties":{
        "name":{
            "title":"姓名",
            "type":"string"
        },
        "age":{
            "title":"年龄",
            "type":"number"
        }
    }
}
复制代码

2、添加校验,例如对姓名有必填要求、最小最大限制,可以按 JSON Schema 规范添加相应关键字,并根据 ajv-errorMessage 添加错误信息。

{
    "type": "object",
  	"required":["name"],
  	"errorMessage":{
     	"required":{
        "name":"必填"
      }
    },
    "properties":{
        "name":{
            "title":"姓名",
            "type":"string",
          	"minLength":2,
          	"maxLength":4,
          	"errorMessage":{
              "minLength":"最小输入2",
              "maxLength":"最大输入4"
            }
        },
        "age":{
            "title":"年龄",
            "type":"number",
        }
    }
}
复制代码

3、增加 UI 描述信息,修改如下:

{
  "type": "object",
  "schema": [
    {
      "title": "姓名",
      "type": "string",
      "minLength": 2,
      "maxLength": 4,
      "requiredMsg": "必填",
      "errorMessage": {
        "minLength": "最小输入2",
        "maxLength": "最大输入4"
      },
      "ui": {
        "type": "text"
      },
      "fieldKey": "name"
    },
    {
      "title": "年龄",
      "type": "number",
      "ui": {
        "type": "number"
      },
      "fieldKey": "age"
    }
  ]
}
复制代码

考虑到开发者配置的简便性,需要对协议进行一些优化,例如:

  • properties 关键字无法满足表单的有序性要求,因此使用 schema 关键字替代 properties 关键字;使用 fieldKey 代替 properties 中的属性。

  • 添加 ui 关键字,ui 是一个对象,用于描述表单控件,其余字段透传主题对应 UI 框架的组件 props 字段。

    {
        //表单控件类型
        type:string,
        //表单标题样式
        title?:TitleStyle,
        //表单提示样式
        description?:Description,
        //表单是否展示
        vcontrol?:string|VcontrolFunc,
        //表单数据变化触发函数体
        onchange?:string|CustomFunc,
        //表单主题
        theme?:string,
        [propName:string]:unknown
    }
    复制代码
  • 由于 JSONSchema 规范中,设置必填和错误文案必须在父级,这无疑增加设置成本。因此 untiedSchema 使用 requiredMsg 代替必填和必填错误文案。

  • 增加表单的全局配置,比如布局 containerStyle 、主题 theme 、校验时机 validateTime

4、最终输出 unitedSchema 如下:

{
  "validateTime": "change",
  "type": "object",
  "theme": "drip-design",
  "schema": [
    {
      "title": "名字",
      "type": "string",
      "minLength": 2,
      "maxLength": 4,
      "errMsg": {
        "minLength": "最小输入2位",
        "maxLength": "最大输入4位",
        "_": "错误兜底文案"
      },
      "ui": {
        "type": "text",
        "placeholder": "请输入姓名",
        "description": {
          "type": "icon",
          "title": "hover触发提示",
          "trigger": "hover"
        }
      },
      "requiredMsg": "必填",
      "fieldKey": "name"
    }
  ]
}
复制代码

上述配置会生成下面表单:

2) 核心

DripForm 的核心模块,用于加载主题包、加载校验插件、全局状态管理、解析协议等。

3) 全局状态管理

DripForm 没有额外引入状态管理库,使用 hooks+immer+memo 等方式管理数据,在顶级组件中通过 useImperativeHandle 提升表单内部所有数据。表单外部可以通过 ref 对象获取到当前表单数据、校验状态、UI 逻辑、校验逻辑、setgetmerge 等。

4) 主题

DripForm 可以通过配置 themeuiComponents 来决定使用的主题,可以单一主题,也可以混合使用主题,开源版本中内置了对主流 UI库 如 antd 的适配,方便大家把 DripForm 无缝接入系统中。

theme 关键字可以在全局配置,也可以在某一个表单的 schema 中配置,表单配置优先级高于全局配置。

5) 校验

校验部分使用 JSON Schema、ajv 实现,前后端开发者可基于 ajv 规范对表单 JSON 进行一致化的校验。默认内置 ajv-errorsajv-formatsajv-keywords@jdfed/drip-form-plugin-formats@jdfed/drip-form-plugin-keywords 等插件,满足常见场景,也可以自行扩展自定义规则的校验插件,补充关键词或更多功能。

6) 可视化生成器

可视化生成器提供 npm 包形式,支持扩展自定义业务组件。表单配置生成分为左侧组件选择、中间视图拖拽区域、右侧配置区域,生成器本身也是由DripForm所生成的。 新增业务组件或者配置已有的组件只需要配置一份 Schema 即可。

DripFormGenerator使用案例

六、 结尾

除持续迭代优化外,DripForm 近期重心会在提供更多开放API、依据数据自动生成表单等方面,并希望能通过开源,与社区一起交流改进。

你的Star是我们最大的动力,如果对项目有兴趣、有建议,欢迎随时与我们交流~

猜你喜欢

转载自juejin.im/post/7042223821218119694