最近做中后台项目,最多的就是表单和表格,业内有很多的集成解决方案,可以学习一番

计划

  • 对比业内基本的表单方案,有赞云,网易云音乐
  • 对比业内的formily,formrender
  • 对比业内的hooks表单方案
  • proform解决方案
  • 深入对比和思考
  • 各种可视化配置的系统,

如何做更深入?

  • 拿一个工作中较复杂的案例,使用几种方案实现一遍,感受一下。子表单,数组表单,复杂联动,校验。

  • 表单解决方案

React 表单源码阅读笔记 - 知乎 👍👍
react 表单方案一览 · 语雀 👍👍
ZooTeam 拍了拍你,来看看如何设计动态化表单 - 政采云前端团队
有赞云-可配置表单的实践 👍👍
面向复杂场景的表单解决方案 - SegmentFault 思否 网易云
一套基于 React Hooks 的表格/表单方案 - 知乎
Meson Form 功能整理 - 知乎

以React表单库Formik为例谈优秀的三方库应该是什么样的 - 知乎 👍👍

Form 组件设计 - 让 Form 表单具备高易用性 - 知乎

https://react-hook-form.com/api/

【问卷】 FormRender 使用场景 · Issue #94 · alibaba/x-render

schema配置方案

  • sula
  • formily
  • form-render
  • 有赞云
  • 网易云

代码方案

  • pro form
  • react hook form

有哪些问题要解决

  • 联动
  • 校验
  • 动态表单 (
  • 满足某些条件提交
  • 新建态,编辑态

  • 自定义样式

一些方案对比

基本能力,基本配置,校验,联动,状态,动态options

网易云音乐 有赞
基本字段描述 key
type 组件
value
校验规则 rules字段,跟随
联动 反向监控,字段变化维护在字段配置本身

listeners字段
watch,condition,set 组合实现联动
反向监控

_show函数,支持同步函数,传入values,返回boolean

_subscribe函数订阅,前后值对比
_subscribe(prevValues, values, restart)

函数restart() 重启组件
状态 通过字段status字段
设置了edit,preview,disabled,hidden四种抽象状态
动态options 定义4种类型
其实是对不同4种逻辑分装,最终形成4种配置

- 对象描述 (变量值,监听值,接口处理描述)
- 编写函数
-

| _fetch_data() 动态获取 | | | children组合类

如radioGroup和radio组合 | | | | | 格式化组件 | | _format函数,返回JSX代码 | |

子表单,表单列表,table表单

网易云音乐 zooTeam
表单列表(数组字段)

table表单
Array组件

type定义Table和Card两种形态

children字段配置子表单
容器组件

表格表单
子表单
自定义组件 组件注册
插槽支持 声明slot插槽ID

渲染时,再插入插槽

各项拆解

联动

几种常见的联动场景

  • 一个表单值,联动另一个表单的显示隐藏。()
  • 一个表单值,联动另一个表单select的下拉选项。(选择男女,请假事由选项不一样)
  • 一个表单值,联动另一个表单的值。(省市联动,省变动需要清空市)

所以需要具备怎样的能力,有哪些解法

过去的代码是如何写的?


动态options

表单列表 table表单

自定义组件 插槽

Formily方案

formily的几个核心概念 | Joyde·zhong的博客

Formily实践 - 知乎 👍👍
formily的几个核心概念 | Joyde·zhong的博客 formily介绍

面向复杂场景的高性能表单解决方案(背景篇) - 知乎 formily介绍
Formily2.0更新概要 · Discussion #1087 · alibaba/formily 2.0
可能是你见过最专业的表单方案—-解密Formily2.0 - 知乎2.0

有哪些核心的概念?

  • effects 副作用
  • 生命周期 ()
  • 暴露actions

1 整体概述
2 联动处理
3 扩展组件

后面的内容主要摘自 Formily实践 - 知乎 👍👍

初步认识 核心概念

Formily 解决方案的本质是构造了一个 Observable Form Graph,在这个 Form Graph 中,我们抽象了整个表单领域模型,同时这个模型又是一个无限循环状态机

Formily

UI和逻辑的分离,

  • 无限循环状态机
  • 基于json-schema描述
  • 描述扩展了多种字段,
  • 数据扩展了多中类型,Array,Object,
  • formPath 基于路径的选择器
  • 基于生命周期的事件监听

基础的描述

基于json-schema扩展的描述
**

  • 基于json-schema的规范,**
  • 但是json-schema主要是数据结构描述,Form组件还涉及到UI描述。
  • 自定义属性,一般以 x- 开头。如通过 x-component 来描述组件,以及 x-component-props 描述组件属性
  • 动态变量,以及计算的一些地方,通过 {{expression}}
  1. <SchemaForm
  2. components={components}
  3. actions={actions}
  4. initialValues={initialValues}
  5. value={value}
  6. defaultValue={defaultValue}
  7. onSubmit={console.log}
  8. effects={effects}
  9. schema={schema}
  10. editable={false}
  11. expressionScope={expressionScope}
  12. >
  13. <FormButtonGroup>
  14. <Submit>提交</Submit>
  15. </FormButtonGroup>
  16. </SchemaForm>

节点类型
**
有两个类型的节点,一种是虚拟节点(VirtualField)和值节点(Field)。即虚拟节点不参与表单values的构建。

有哪些组件类型?

  • Form
  • Field
  • VirtualField

联动处理

Formily 官方的实现复杂联动

formily无限循环状态机。字段间的联动有如下特点:

  • 任何联动都是从表单生命周期而发起。
  • 任何联动都需要一个路径来描述具体字段,这个路径可认为是选择器。
  • 联动的最终是操作具体字段的状态。(包括默认状态,扩展状态,值,组件属性)

状态

声命周期
**
生命周期分两类,有表单Form声明周期和字段Field生命周期

组件状态
**
有非常多的状态集合,联动目的就是操作字段的状态

如action相关 loading,validating,submiting(只有form支持),
如展示相关,editable,display(字段值可以被提交),visible (字段值不提交)
如状态 errors,warnings,
如值相关 value,values
如交互事件相关,active,visited,
如校验,rules,ruleWarnings,ruleErrors
如属性,name,props,dataType,path

自定义扩展状态

路径选择 FormPath

动态匹配能力

部分通配 “a.b..c”
分组通配 “a.b.(aa.bb.dd,cc,mm)”
范围通配 “a.b.*[10:100]”

字段校验

联动校验
**
Formily实践 - 知乎

快捷联动写法 x-linkages

编写业务逻辑 上下文环境

  • SchemaForm外部,通过暴露的actions访问
  • SchemaForm中effects定义的逻辑,一切逻辑从生命周期开始
  • 自定义组件中

子表单嵌套 Array表单

Formily 自增列表组件,有ArrayCards,ArrayTable
https://formilyjs.org/#/0yTeT0/wWuyuJc6fO 自增列表 & 联动,有相应的逻辑
Formily 学习6(自增列表联动)_Qg520jungle的博客-CSDN博客

  1. <SchemaForm
  2. components={{ ArrayTable, Input, Select }}
  3. >
  4. <Field type="array" name="array" x-component="ArrayTable">
  5. <Field type="object">
  6. <Field type="string"
  7. name="aa"
  8. title="Sibling visible"
  9. >
  10. </Field>
  11. </Field>
  12. </Field>
  13. </SchemaForm>

React组件

扩展组件 组件内实现

组件内部是如何实现的?如Array

一个联动DEMO

  1. import { FormEffectHooks, createFormActions } from '@formily/next'
  2. const { setFieldState, getFieldState } = createFormActions()
  3. const { onFieldValueChange$, onFormInit$ } = FormEffectHooks
  4. onFieldValueChange$('*(password,confirm)').subscribe(fieldState => {
  5. const selfName = fieldState.name
  6. const selfValue = fieldState.value
  7. const otherName = selfName == 'password' ? 'confirm' : 'password'
  8. const otherValue = getFieldState(otherName, state => state.value)
  9. setFieldState(otherName, state => {
  10. if (selfValue && otherValue && selfValue !== otherValue) {
  11. state.errors = '两次密码输入不一致'
  12. } else {
  13. state.errors = ''
  14. }
  15. })
  16. setFieldState(selfName, state => {
  17. if (selfValue && otherValue && selfValue !== otherValue) {
  18. state.errors = '两次密码输入不一致'
  19. } else {
  20. state.errors = ''
  21. }
  22. })
  23. })

2.0更新

Formily2.0更新概要 · Discussion #1087 · alibaba/formily

表格解决方案

GitHub - x-extends/vxe-table: 🐬 vxe-table vue 表格解决方案
ProTable 快速搭建 CRUD 的利器 - Ant Design Pro 👍👍 直接阅读和思考
ProTable - 高级表格 文档,看一些案例来更深入的理解
alibaba/alist: Alibaba Group Unified List Solution.

表格有哪些点? 或者说CRUD

数据请求 (在筛选,翻页等情况会重置页数,重发请求)

  • 筛选框

对下面数据的筛选,选择后筛选,或点击查询时筛选

筛选框中功能按钮,重置,查询

  • 功能框()

其它操作,新建,
批量操作,批量删除,批量操作

  • 列表内容区

各种不同的格式化类型,时间,金钱,
特殊渲染,特殊样式,
也有操作,编辑,删除等

  • 可折叠table

  • 可编辑table

  • 翻页区