第一次使用antd pro框架,第一个想法是:居然有这么一个对表单数据处理方便的框架,开心的一逼,然后就开始了坎坷的开发之路。话不多说上代码。
我要开发的功能模块如下图所示:自定义地址组件开发.
提交的数据格式为:
// form表单的数据格式
params = {
companyAddressList: [{
country: '中国',
province: '浙江',
city: '杭州',
area: '西湖区',
street: '*****',
postcode: '*****',
defaultStatus: false,
},{
country: '中国',
province: '浙江',
city: '杭州',
area: '西湖区',
street: '*****',
postcode: '*****',
defaultStatus: false,
}],
billAddressList: [{
country: '中国',
province: '浙江',
city: '杭州',
area: '西湖区',
street: '*****',
postcode: '*****',
defaultStatus: false,
}, ],
receiptAddressList: []
}
首先,表单最外层需要 ProForm 标签,用来进行最后的提交操作。
<ProForm
className="hy-form-container"
formRef={formRef}
name="hy-form"
layout="vertical"
onFinish={onSumitForm} // 提交方法
>
<HYSchemaForm formRef={formRef} /> // 在该组件里面写子方法
</ProForm>
我是用 Segmented 来模拟客户地址、账号地址和收货地址。
const addressNameList = [
{
title: '客户地址',
dataIndex: 'companyAddressList',
},
{
title: '账单地址',
dataIndex: 'billAddressList',
},
{
title: '收货地址',
dataIndex: 'receiptAddressList',
},
];
const { formRef } = props;
const [activeAddressType, setActiveAddressType] = useState('客户地址');
const addressOptions = addressNameList.map((item) => {
return item.title;
});
<Segmented
size="large"
options={addressOptions}
onChange={(value: string | number) => {
setActiveAddressType(value as string);
}}
/>
下面就是列表的渲染。需要注意的点有这么几个(详见代码注释):
const actionRef = [useRef(), useRef(), useRef()];
<div className="address-form-list">
{addressNameList && addressNameList.length ?
addressNameList.map((item, index) => {
const isShowFormList = activeAddressType === item.title;
return (
<ProFormList
actionRef={actionRef[index]} // addressNameList有三个数据,所以useRef()需要定义三次
key={item.dataIndex}
name={item.dataIndex} // name用上传数据的字段名,比如companyAddressList
copyIconProps={false} // 复制按钮不展示
initialValue={[{}]} // 初始化数据
fieldExtraRender={(fieldAction) => {
// 自定义新增地址按钮
return (
<Button icon={<PlusOutlined />} onClick={() => fieldAction.add({})}>
新增地址
</Button>
);
}}
creatorButtonProps={false}
actionRender={(field) => {
return [
/**
* 这里会遇到一个大坑
* key值要用field.name,而不用field.key
* field.name相当于数组的index下标
*/
<a
style={{ color: '#FF4218' }}
key={field.name}
onClick={() => actionRef[index]?.current?.remove(field.name)}
>
<DeleteOutlined />
删除
</a>,
];
}}
deleteIconProps={false}
style={{ display: isShowFormList ? 'flex' : 'none' }} // 模拟列表的显示隐藏
>
// 这块代码也很重要:将index传到子模块中,当做子模块的key
{(
meta,
// 当前的行号
groupIndex: number,
) => {
return renderGroups(groupIndex);
}}
</ProFormList>
);
})
: null}
</div>
最后,将group内容渲染出来,其中要注意的是,name是对应的字段名称。
// 获取对应字段的列表数据并返回
const getAllAddressInfo = (list: any) => {
return list.map((item: any) => {
return formRef?.current?.getFieldValue(item);
});
};
// 此处是将companyAddressList数据复制到另外两个数组中
const setAllAddress = (index: number) => {
const dataIndexList = addressNameList.map((item) => {
return item.dataIndex;
});
const [companyAddressList, billAddressList, receiptAddressList] = getAllAddressInfo(dataIndexList);
formRef.current?.setFieldsValue({
billAddressList: billAddressList.concat(companyAddressList[index]),
receiptAddressList: receiptAddressList.concat(companyAddressList[index]),
});
};
const renderGroups = (index: any) => {
return (
<ProForm.Group key={index}>
<ProFormText name="country" label="国家" width={120} />
<ProFormText name="province" label="省份" width={100} />
<ProFormText name="city" label="市" width={100} />
<ProFormText name="area" label="区" width={100} />
<ProFormText name="street" label="街道详细地址" width={260} />
<ProFormText name="postcode" label="邮编" width={150} />
<div className="address-container">
<ProFormCheckbox name="defaultStatus" label=" ">
默认地址
</ProFormCheckbox>
{activeAddressType === addressNameList[0]?.title ? (
<Checkbox
onChange={() => {
setAllAddress(index);
}}
>
同时设置为账单地址/公司地址
</Checkbox>
) : null}
</div>
</ProForm.Group>
);
};
了解pro的写法,在表单开发中还是非常方便的。