一、概述
Antd是一个非常强大的UI组件库,里面的Form
表单组件也基本能满足我们大多数场景。但是也有需要自定义表单的场景。
-
Vue2
里我们使用v-model
,结合子组件的model
属性,来实现自定义组件的双向绑定。 -
Vue3
里我们使用v-model
,结合子组件的update:modelValue
来实现同样功能。 -
到了
React+Antd
中,我们采用引用父组件默认传入onChange
事件,子组件调用来实现。
二、开发实现
1、代码
父组件代码:
tsx
import { Button, Space, Form, Input, Radio, Switch } from "antd";
import MyBtns from "./components/myBtns";
import { useState, useEffect } from "react";
function Index() {
const [form] = Form.useForm();
const [formData, setFormData] = useState<Object>({});
const layout = {
name: "myFrom",
autoComplete: "off",
labelCol: {
span: 3,
},
wrapperCol: {
span: 21,
}
};
const initData = {
title: "IT飞牛的自定义表单",
item1: "选项-2",
};
const onFinish = async (values: Object) => {
//提交数据
//...
}
const onReset = () => {
form.resetFields();
};
useEffect(() => {
setFormData(initData);
}, [])
return <div>
{JSON.stringify(formData)}
<Form
onFinish={onFinish}
onValuesChange={(changedValues, allValues) => { setFormData(allValues) }}
form={form}
labelAlign="right"
initialValues={initData}
style={{
"marginTop": "50px"
}}
{...layout}
>
<Form.Item name="title" label="标题">
<Input />
</Form.Item>
<Form.Item name="item1" label="自定义项">
<MyBtns />
</Form.Item>
<Form.Item wrapperCol={{ offset: 3, span: 21 }}>
<Space size="middle">
<Button htmlType="button" onClick={onReset}>
取消
</Button>
<Button type="primary" htmlType="submit">
提交
</Button>
</Space>
</Form.Item>
</Form>
</div >
}
export default Index;
子组件(myBtns.tsx)代码:
tsx
import { Button, Space } from "antd";
const myBtns = (props: any) => {
const { value, onChange } = props //value 是form表单中"name"对应的字段值
const onSelected = (val: string) => {
onChange(val)
}
const getTypeClass = (val: string) => {
return value == val ? "default" : "dashed";
}
return <Space>
<Button type={getTypeClass("选项1")} onClick={() => onSelected("选项1")}>选项1</Button>
<Button type={getTypeClass("选项2")} onClick={() => onSelected("选项2")}>选项2</Button>
<Button type={getTypeClass("选项3")} onClick={() => onSelected("选项3")}>选项3</Button>
</Space>
}
export default myBtns;
2、最终效果
可以看到,表单中有两个选项,第一个是Input
组件,第二个是自定义组件MyBtns
,已经实现数据的事实更新。
3、原理
Form.Item
在渲染时会注入 value
与 onChange
事件给子元素。
- value:
form.item
对应的name
属性的值,可用作默认值以及返显 - onChange:用于监听
value
元素值的变化,并将其传给form.item
使其可以通过相关api获得其值
注意:当你的字段组件被包裹时属性将无法传递。所以以下代码是不会生效的:
tsx
<Form.Item name="input">
<div>
<h3>I am a wrapped Input</h3>
<Input />
</div>
</Form.Item>