react+antd 开发一个可动态增减的复合组件
需求如图:
![](https://img2022.cnblogs.com/blog/1395328/202210/1395328-20221021142912435-401715653.jpg)
与后端协商好的表单数据为:
组件代码:
/* 阶梯分成组件 */ import React, { useState, useEffect } from 'react'; import { message, InputNumber, Button } from 'antd'; import { PlusOutlined, DeleteOutlined } from '@ant-design/icons'; import styles from './Condition.less'; let rowKey = 0; type ConfigProps = { unit?: string; afterText?: string; precision?: number; key?: string; }; const Condition: React.FC<any> = (props) => { const { value, maxLength, config, onChange } = props; const [dataList, setDataList] = useState<any[]>([{ rowKey }]); // 新增 const handleAdd = () => { if (dataList && dataList.length <= maxLength) { if (!rowKey) rowKey = dataList.length || 0; rowKey += 1; const keyObj = {}; config.map((item: ConfigProps) => { if (item.key) keyObj[item.key] = undefined; }); const newObj = { ...keyObj, rowKey }; setDataList([...dataList, newObj]); if (onChange) { onChange([...dataList, newObj]); } } else { message.error('已达添加上限'); } }; // 删除 const handleDelete = (_key: any) => { setDataList(dataList.filter((it: any) => it.rowKey !== _key)); if (onChange) { onChange(dataList.filter((it: any) => it.rowKey !== _key)); } }; // 要求整数 // const limitDecimals = (values?: string | number | undefined) => { // if (values) return String(values).replace(/^(0+)|[^\d]+/g, ''); // return ''; // }; // 改变值 const handleNumber = (_value: number | string | null, data: any, key: string) => { const newList = dataList.map((it) => { if (it.rowKey === data.rowKey) { return { ...it, [key]: _value }; } return it; }); setDataList(newList); if (onChange) { onChange(newList); } }; // 监听默认值更新 useEffect(() => { if (value && value.length > 0) { setDataList(value); } }, []); return ( <div className={styles['m-condition']} style={{ maxHeight: dataList.length > 10 ? '432px' : 'auto', overflowY: dataList.length > 10 ? 'scroll' : 'auto', }} > {dataList && dataList.map((item: any, index: number) => ( <div key={`${item.rowKey}${item.tips}`} style={{ marginBottom: '8px' }}> <div style={{ width: '100%', display: 'flex', justifyContent: 'flex-start', alignItems: 'center', }} > {config?.map((itemConfig: any, indexConfig: number) => { return ( <span key={itemConfig.afterText} style={{ display: 'inline-flex', alignItems: 'center' }} > <InputNumber max={ indexConfig === 0 ? item[config[1].key] || itemConfig.max : itemConfig.max } min={ indexConfig === 1 ? item[config[0].key] || itemConfig.min : itemConfig.min } style={{ width: '140px', marginLeft: indexConfig === 0 ? 0 : '8px', marginRight: '8px', }} precision={itemConfig.precision} placeholder={'请输入'} value={itemConfig.num} onChange={(values) => handleNumber(values, item, itemConfig.key)} key="NumberMin" addonAfter={itemConfig.unit} /> <span>{itemConfig.afterText}</span> </span> ); })} <DeleteOutlined onClick={() => handleDelete(item.rowKey)} style={{ marginLeft: '8px', visibility: index === 0 ? 'hidden' : 'visible' }} /> </div> </div> ))} <Button type="dashed" onClick={handleAdd} style={{ width: '100%' }} icon={<PlusOutlined />} disabled={maxLength && dataList && dataList.length && dataList.length >= maxLength} > 新增阶梯 </Button> </div> ); }; export default Condition;
.m-condition { &::-webkit-scrollbar { width: 4px; } &::-webkit-scrollbar-thumb { background: #e3e8ee; border-radius: 10px; } &::-webkit-scrollbar-track-piece { background: transparent; } }
引用:
在存储表单组件的dataSource数组时,遍历render: if (el.id === 'xxx') { return { ...el, renderFormItem: () => <Condition />, }; }
传递的数据格式为: