I. Overview
Antd is a very powerful UI component library, and Form
the form components in it can basically meet most of our scenarios. But there are also scenarios where custom forms are required.
-
Vue2
Here we usev-model
, combined with the properties of sub-componentsmodel
, to implement two-way binding of custom components. -
Vue3
Here we usev-model
, combined with subcomponentsupdate:modelValue
to achieve the same function. -
In the middle
React+Antd
, we use the default incomingonChange
event referenced by the parent component and call it by the child component.
2. Development and implementation
1. Code
Parent component code:
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;
Subcomponent (myBtns.tsx) code:
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. Final effect
As you can see, there are two options in the form, the first is Input
a component, and the second is a custom component MyBtns
, which has implemented factual updating of data.
3. Principle
Form.Item
value
Events will be injected into child elements when rendering onChange
.
- value: The value of the
form.item
correspondingname
attribute, which can be used as the default value and return display - onChange: used to monitor
value
changes in element values and pass them onform.item
so that their values can be obtained through relevant APIs
Note: Properties will not be passed when your field component is wrapped. So the following code will not take effect:
<Form.Item name="input">
<div>
<h3>I am a wrapped Input</h3>
<Input />
</div>
</Form.Item>