前言
在前端中后台的开发中,常见的业务场景是对表单的处理。对于简单、交互少、联动少的业务场景直接使用antd
提供的Form
组件就可以,对于追求性能,需要复杂表单生成的时候可以使用 formily 开源库
,但其付出的学习成本会更高。
今天介绍一个本人开源的项目,介于两者之间的一个便捷、高效、易于理解、且功能相对完整、适用于绝大多数业务场景开发的一个库。
这是一个纯前端的项目
github地址
github演示地址
cmg-ceo.github.io/antdform.gi...
功能一:配置化生成表单
简化了Form
组件的写法,原来写法,要在每一个Form里面写Form.item 并在Form.Item 内写一堆配置项
jsx
<Form
name="basic"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="标题"
name="title"
rules={[{ required: true, message: 'Please input your username!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="备注"
name="remark"
rules={[{ required: true, message: 'Please input your password!' }]}
>
<Input.Password />
</Form.Item>
</Form>
我们对其进行了精简化操作 ,将需要传入的配置项抽象成一个数组对象 fields
,进行传递,这样带来的好处就是代码书写更加清晰,同时使用了数组对象形式,带来更加便捷的修改使用。
jsx
<Form form={form} layout="vertical" initialValues={{}}>
<FormItem
ref={form}
fields={[
{
type: 'text',
required: true,
label: '标题',
code: 'title',
span: 24,
},
{
type: 'textarea',
label: '备注',
code: 'remark',
span: 10,
},
]}
labelCol={24}
wrapperCol={24}
></FormItem>
</Form>
- ref 为表单实例项
- fields 表单内每一控件的配置信息
- labelCol、wrapperCol 每一项的标签和输入控件的布局样式
功能二 采用组的概念实现数据联动
表单之间的数据联动是非常常用的功能,例如一个表单中有一个选择控件,希望选择一的时候后面展示输入框一,选择二的时候后面展示选择框二。
这里的设计模式是:
将所有的表单控件都传递到fields字段中,并传入相对应的组的名称。
就拿上面例子来说,fields
传入所有有可能展示的对象(选择框控件,输入框一、输入框二),在选择控件的点击事件中,设置对应的 groupValue
值,在输入框一、二中 group 设置不同组的名称。
这样是通过组关联起来group、 groupValue
支持字符串数组
同样一个控件可由多个规则控制。
jsx
const [groupValue, setGroupValue] = useState([]);
...
<FormItem
ref={form}
fields={[
{
type: 'select',
required: true,
label: '规则选择(一)',
code: 'rules1',
span: 24,
options: [
{
id: '1-1',
name: '规则1-1',
},
{
id: '1-2',
name: '规则1-2',
},
],
onChange: (val) => {
// 获取选中的值,根据业务需求更新组的规则
const index = groupValue.findIndex((i) => i === '1-1' || i === '1-2');
if (index > -1) {
groupValue.splice(index, 1, val);
} else {
groupValue.push(val);
}
setGroupValue([...groupValue]);
},
},
{
type: 'select',
required: true,
label: '规则选择(二)',
code: 'rules2',
span: 24,
options: [
{
id: '2-1',
name: '规则2-1',
},
{
id: '2-2',
name: '规则2-2',
},
],
onChange: (val) => {
// 获取选中的值,根据业务需求更新组的规则
const index = groupValue.findIndex((i) => i === '2-1' || i === '2-2');
if (index > -1) {
groupValue.splice(index, 1, val);
} else {
groupValue.push(val);
}
setGroupValue([...groupValue]);
},
},
{
type: 'text',
label: '我是规则1-1',
code: 'rule1-1',
span: 24,
// 所属组
group: ['1-1'],
},
{
type: 'text',
label: '我是规则1-2或2-1',
code: 'rule1-2,2-1',
span: 24,
// 所属组
group: ['1-2', '2-1'],
},
{
type: 'text',
required: true,
label: '规则2-2 必填',
code: 'rule2-2',
span: 24,
group: ['2-2'],
},
{
type: 'text',
label: '规则不是2-2 非必填',
code: 'rule2-2',
span: 24,
group: ['1-1', '1-2', '2-1'],
},
]}
groupValue={groupValue}
labelCol={24}
wrapperCol={24}
></FormItem>
功能三 一级列表
在Antd Form
的动态增减表单项基础上衍生出的功能
一级列表的功能和 Antd 基本一致,将Antd的代码进行封装使其更加清晰简洁
这里,level1
的字段内容就是你要新增的一级列表的内容
同时这里封装了addLevel1
方法,你只需要调用它就可以生成
jsx
import FormItem, { FormWrapCard, addLevel1 } from '@/components/FormItem';
...
const addHandle = () => {
// 将form实例,一级列表的名称,一级列表需要赋值的初始值传递下去
addLevel1(form, ['list'], {});
};
<Form form={form} layout="vertical" initialValues={{}}>
<FormItem
ref={form}
fields={[
{
type: 'text',
required: true,
label: '标题',
code: 'title',
span: 24,
},
]}
level1={{
name: ['list'],
fields: [
{
type: 'text',
label: '键',
code: 'key',
span: 12,
},
{
type: 'text',
label: '值',
code: 'value',
span: 12,
},
],
WrapComponent: FormWrapCard,
// 列表的复制功能
wrapCopy: true,
// 列表的移动功能
wrapMove: true,
// 列表的是否展示label,不展示时显示类似于表格
openLabel: true,
}}
labelCol={24}
wrapperCol={24}
></FormItem>
</Form>
<Button onClick={addHandle}> 添加一项</Button>
功能四 二级列表
在一级列表的功能上,进一步实现二级列表的开发,及嵌套在一级列表中的列表
其中使用 addLevel2
方法,生成
jsx
import FormItem, { FormWrapCard, addLevel1, addLevel2 } from '@/components/FormItem';
// ...
const addHandle = () => {
addLevel1(form, ['list'], {});
};
const addHandleLevel2 = (field) => {
const name = ['level2'];
// 新增第二级的List
// 将form实例,二级列表的名称(第一项为一级列表的名称),二级列表需要赋值的初始值传递下去
addLevel2(form, ['list', field.name], name, {});
};
return (
<>
<Divider orientation="left">表单二级</Divider>
<Form form={form} layout="vertical" initialValues={{}}>
<FormItem
ref={form}
level1={{
name: ['list'],
fields: [
{
type: 'text',
label: '我是Level1',
code: 'level1',
span: 24,
},
],
WrapComponent: FormWrapCard,
openLabel: true,
wrapAction: (data) => <PlusCircleOutlined onClick={() => addHandleLevel2(data)} />,
}}
level2={{
name: ['level2'],
fields: [
{
type: 'text',
label: '我是Level2',
code: 'level1',
span: 10,
},
],
openLabel: true,
}}
labelCol={24}
wrapperCol={24}
></FormItem>
</Form>
<Button onClick={addHandle}> 添加一项</Button>
</>
);
功能五 一级列表和二级列表的数据联动
这一块就参考Readme
文档,写的还算详细
待完善
后续还要完成如下功能的开发
-
1、主分支适配
Antd5
版本的,现有的移入Antd4版本分支 (看官网 5在表单控件上改动量并不大) -
2、上
TypeScript
,现有还是JavaScript
开发,后续用上TypeScript
给与更多提示和完善
最后
希望大家点点star,也欢迎大家提出意见一起改进!
其实项目4-5个月前开发好了,但是一直没有写文章推广,因为我失业了,最近才找到新工作,有点时间才写了这篇文章。