一、构造组件
1、表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等。
这里先引用了封装的表单域 <Form.Item />
2、使用Form.create处理后的表单具有自动收集数据并校验的功能,但如果不需要这个功能,或者默认的行为无法满足业务需求,可以选择不使用Form.create并自行处理数据
经过Form.create()包装过的组件会自带this.props.form属性,this.props.form提供了很多API来处理数据,如getFieldDecorator——用于和表单进行双向绑定等,详细参加Antd官方文档:点击此处查看
先展示表单样式:
import React from 'react';
import {Form, Table, Button, Select, Input, DatePicker} from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const {RangePicker} = DatePicker;//获取日期选择控件中的日期范围控件
class UserManage extends React.Component {
render() {
const columns = [
{
title: '联系人',
dataIndex: 'userName',
key: 'userName',
}, {
title: '手机号',
dataIndex: 'mobile',
key: 'mobile',
}, {
title: '公司名称',
dataIndex: 'companyName',
key: 'companyName',
}, {
title: '最近活跃时间',
dataIndex: 'lastOnlineTime',
key: 'lastOnlineTime',
}, {
title: '禁言状态',
dataIndex: 'status',
key: 'status',
},
];
return (
<div>
<Form layout="inline" style={{marginBottom: '10px'}}>
<FormItem label="最近活跃时间">
<RangePicker style={{width: '255px'}}/>
</FormItem>
<FormItem label="用户">
<Input type="text" placeholder="公司名称、手机号" style={{width: '155px'}}/>
</FormItem>
<FormItem label="禁言状态">
<Select defaultValue="全部" style={{width: '155px'}}>
<Option value="全部">全部</Option>
<Option value="是">是</Option>
<Option value="否">否</Option>
</Select>
</FormItem>
<Button type="primary" style={{marginTop: '3px', marginRight: '3px'}}>查询</Button>
<Button style={{marginTop: '3px'}}>重置</Button>
</Form>
<Table
columns={columns}
/>
</div>
)
}
}
export default Form.create()(UserManage)
colums是Table组件的API,columns和Column组件使用相同的API:
dataIndex:列数据在数据项中对应的 key,支持a.b.c的嵌套写法
key:React 需要的 key,如果已经设置了唯一的dataIndex,可以忽略这个属性
二、使用getFieldDecorator(id, options) 进行表单交互
1、现在的问题就是如何获取各种查询条件的数据,所以先改写render()里面的代码,getFieldDecorator用于和表单进行双向绑定:
...
render(){
const {form} = this.props;
const {getFieldDecorator} = form;
...
return (
<div>
<Form onSubmit={this.handleQuery} layout="inline" style={{marginBottom: '10px'}}>
<FormItem label="最近活跃时间">
{getFieldDecorator('lastOnlineTime')(<RangePicker style={{width: '255px'}}/>)}
</FormItem>
<FormItem label="用户">
{getFieldDecorator('userQueryLike')(<Input type="text" placeholder="公司名称或手机号" style={{width: '155px'}}/>)}
</FormItem>
<FormItem label="禁言状态">
{getFieldDecorator('status', {initialValue: "全部"})(
<Select style={{width: '155px'}}>
<Option value="0">全部</Option>
<Option value="1">是</Option>
<Option value="2">否</Option>
</Select>)}
</FormItem>
<Button type="primary" htmlType="submit" style={{marginTop: '3px', marginRight: '3px'}}>查询</Button>
<Button style={{marginTop: '3px'}}>重置</Button>
</Form>
<Table
columns={columns} /*dataSource={(从model取得的数据)}*/
/>
</div>
)
}
...
参数 | 说明 | 类型 | 默认值 |
id | 必填输入控件唯一标志。支持嵌套式的写法。 | string | |
options.getValueFromEvent | 可以把 onChange 的参数(如 event)转化为控件的值 | function(..args) | reference |
options.initialValue | 子节点的初始值,类型、可选值均由子节点决定(注意:由于内部校验时使用 | ||
options.normalize | 转换默认的 value 给控件 | function(value, prevValue, allValues): any | - |
options.rules | 校验规则,详细参考Antd官方文档 | object[] | |
options.trigger | 收集子节点的值的时机 | string | 'onChange' |
options.validateFirst | 当某一规则校验不通过时,是否停止剩下的规则的校验 | boolean | false |
options.validateTrigger | 校验子节点值的时机 | string|string[] | 'onChange' |
options.valuePropName | 子节点的值的属性,如 Switch 的是 'checked' | string | 'value' |
2、上面给了表单一个onSubmit事件,当表单提交时执行handleQuery方法:
...
class UserManage extends React.Component {
//表单查询
handleQuery = (e) => {
if (e) e.preventDefault();
const {dispatch, form} = this.props;
form.validateFields((err, fieldsValue) => {
if (err) return;
//获取时间范围的值
const rangeValue = fieldsValue['lastOnlineTime'];
const userQueryLike = fieldsValue['userQueryLike'];
//获取查询条件
const values = {
...fieldsValue,
"lastOnlineTime": (rangeValue && rangeValue.length > 1) ?
([rangeValue[0].format('YYYY-MM-DD'), rangeValue[1].format('YYYY-MM-DD')]) : null,
"userQueryLike": userQueryLike ? userQueryLike.trim() : userQueryLike,
};
dispatch({
type: "userManageModel/getUserList",
payload: {
values: values,
}
});
});
};
...
}
...
在此方法里又调用了form.validateFields校验并获取一组输入域的值与Error,入参fieldsValue就是从表单的FormItem里取到的值,然后使用fieldsValue['lastOnlineTime']这种形式,通过与之前写的getFieldDecorator('lastOnlineTime')产生映射,就获取了单个输入域的值。
总结一下,使用React的Form实现表单功能,必须要使用Form.create(组件),使包装的组件带有this.props.form属性,才能调用form的getFieldDecorator和validateFields方法,getFieldDecorator中的id对应validateFields中的fieldsValue[''];而columns中的dateIndex对应的是从model取到数据json串的键名,这个要分清
========2021.8.2 更新========
现在ant.design已进入V4版本,form的使用更加简便,不再需要HOC式写法 Form.create()(XXX),
//V4
import React form 'react;
import {Form, Input, Button} from 'antd';
import { FormInstance } from 'antd/lib/form';
const Demo: React.FC = () => {
const [myForm] = Form.useForm();
//打印form表单域输入值
console.log(myForm.getFieldsValue());
return (
<Form form={myForm}>
<Form.Item name="version" label="version">
<Input />
</Form.Item>
</Form>
)
}
class Demo1 extends React.component {
formRef = React.createRef<FormInstance>();
onSubmit = () => {
console.log(this.formRef.current);
};
render() {
return (
<Form ref={this.formRef}>
<Form.Item name="version" label="version">
<Input />
</Form.Item>
<Button htmlType="button" onClick={this.onSubmit}>
Submit
</Button>
</Form>
)
}
}
api的使用和原来差不多,具体可参考文档
========2023.2.17 更新========
现在ant.design已进入V5版本,表单基础用法和V4基本一致,代码示例如下:
1.函数组件:
//函数组件
import { Button, Form, Input, Select } from 'antd';
import React from 'react';
const { Option } = Select;
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },
};
const tailLayout = {
wrapperCol: { offset: 8, span: 16 },
};
const App: React.FC = () => {
const [form] = Form.useForm();
const onGenderChange = (value: string) => {
switch (value) {
case 'male':
form.setFieldsValue({ note: 'Hi, man!' });
break;
case 'female':
form.setFieldsValue({ note: 'Hi, lady!' });
break;
case 'other':
form.setFieldsValue({ note: 'Hi there!' });
break;
default:
}
};
const onFinish = (values: any) => {
console.log(values);
};
const onReset = () => {
form.resetFields();
};
const onFill = () => {
form.setFieldsValue({ note: 'Hello world!', gender: 'male' });
};
return (
<Form
{...layout}
form={form}
name="control-hooks"
onFinish={onFinish}
style={{ maxWidth: 600 }}
>
<Form.Item name="note" label="Note" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="gender" label="Gender" rules={[{ required: true }]}>
<Select
placeholder="Select a option and change input text above"
onChange={onGenderChange}
allowClear
>
<Option value="male">male</Option>
<Option value="female">female</Option>
<Option value="other">other</Option>
</Select>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.gender !== currentValues.gender}
>
{({ getFieldValue }) =>
getFieldValue('gender') === 'other' ? (
<Form.Item name="customizeGender" label="Customize Gender" rules={[{ required: true }]}>
<Input />
</Form.Item>
) : null
}
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
<Button type="link" htmlType="button" onClick={onFill}>
Fill form
</Button>
</Form.Item>
</Form>
);
};
export default App;
2.Class组件
//Class组件
import React from 'react';
import { Button, Form, Input, Select } from 'antd';
import type { FormInstance } from 'antd/es/form';
const { Option } = Select;
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },
};
const tailLayout = {
wrapperCol: { offset: 8, span: 16 },
};
const App: React.FC = () => {
const formRef = React.useRef<FormInstance>(null);
const onGenderChange = (value: string) => {
switch (value) {
case 'male':
formRef.current?.setFieldsValue({ note: 'Hi, man!' });
break;
case 'female':
formRef.current?.setFieldsValue({ note: 'Hi, lady!' });
break;
case 'other':
formRef.current?.setFieldsValue({ note: 'Hi there!' });
break;
default:
break;
}
};
const onFinish = (values: any) => {
console.log(values);
};
const onReset = () => {
formRef.current?.resetFields();
};
const onFill = () => {
formRef.current?.setFieldsValue({ note: 'Hello world!', gender: 'male' });
};
return (
<Form
{...layout}
ref={formRef}
name="control-ref"
onFinish={onFinish}
style={{ maxWidth: 600 }}
>
<Form.Item name="note" label="Note" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="gender" label="Gender" rules={[{ required: true }]}>
<Select
placeholder="Select a option and change input text above"
onChange={onGenderChange}
allowClear
>
<Option value="male">male</Option>
<Option value="female">female</Option>
<Option value="other">other</Option>
</Select>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.gender !== currentValues.gender}
>
{({ getFieldValue }) =>
getFieldValue('gender') === 'other' ? (
<Form.Item name="customizeGender" label="Customize Gender" rules={[{ required: true }]}>
<Input />
</Form.Item>
) : null
}
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
<Button type="link" htmlType="button" onClick={onFill}>
Fill form
</Button>
</Form.Item>
</Form>
);
};
export default App;