最近做中后台项目,最多的就是表单和表格,业内有很多的集成解决方案,可以学习一番
计划
- 对比业内基本的表单方案,有赞云,网易云音乐
- 对比业内的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 中,我们抽象了整个表单领域模型,同时这个模型又是一个无限循环状态机
UI和逻辑的分离,
- 无限循环状态机
- 基于json-schema描述
- 描述扩展了多种字段,
- 数据扩展了多中类型,Array,Object,
- formPath 基于路径的选择器
- 基于生命周期的事件监听
基础的描述
基于json-schema扩展的描述
**
- 基于json-schema的规范,**
- 但是json-schema主要是数据结构描述,Form组件还涉及到UI描述。
- 自定义属性,一般以
x-
开头。如通过x-component
来描述组件,以及x-component-props
描述组件属性 - 动态变量,以及计算的一些地方,通过 {{expression}}
<SchemaForm
components={components}
actions={actions}
initialValues={initialValues}
value={value}
defaultValue={defaultValue}
onSubmit={console.log}
effects={effects}
schema={schema}
editable={false}
expressionScope={expressionScope}
>
<FormButtonGroup>
<Submit>提交</Submit>
</FormButtonGroup>
</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博客
<SchemaForm
components={{ ArrayTable, Input, Select }}
>
<Field type="array" name="array" x-component="ArrayTable">
<Field type="object">
<Field type="string"
name="aa"
title="Sibling visible"
>
</Field>
</Field>
</Field>
</SchemaForm>
React组件
扩展组件 组件内实现
组件内部是如何实现的?如Array
一个联动DEMO
import { FormEffectHooks, createFormActions } from '@formily/next'
const { setFieldState, getFieldState } = createFormActions()
const { onFieldValueChange$, onFormInit$ } = FormEffectHooks
onFieldValueChange$('*(password,confirm)').subscribe(fieldState => {
const selfName = fieldState.name
const selfValue = fieldState.value
const otherName = selfName == 'password' ? 'confirm' : 'password'
const otherValue = getFieldState(otherName, state => state.value)
setFieldState(otherName, state => {
if (selfValue && otherValue && selfValue !== otherValue) {
state.errors = '两次密码输入不一致'
} else {
state.errors = ''
}
})
setFieldState(selfName, state => {
if (selfValue && otherValue && selfValue !== otherValue) {
state.errors = '两次密码输入不一致'
} else {
state.errors = ''
}
})
})
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
翻页区