页面样式如图:
一进这个抽屉页面就默认打开第一个折叠面板,点击Add按钮可以新增一个折叠面板,点击Delete按钮可以删除该折叠面板。一个折叠面板里面包含两个下拉框,这两个下拉框的数量是固定的,不固定的是有操作那一块的表单数量,这里表单通过点击操作里面的加号和减号可对应的进行增减。
先贴框架的代码:
<Form
form={form}
name='tableForm'
>
<Button
key='add'
type='primary'
onClick={() => addFormList()}
>
Add
</Button>
// 把折叠框的结构分离出去
<Collapse defaultActiveKey={['0']}>{panelMap}</Collapse>
</Form>
折叠面板的代码:
// 折叠面板的代码
const panelMap = useMemo(() => {
// 下拉框的表单(第一行)
return panels?.map((item, idx) => {
return (
<Panel
header={item.title}
key={item.key}
extra={getExtraBtn(item.key)}
forceRender={true} // 隐藏折叠面板时要渲染DOM,否则被隐藏的表单拿不到数据
>
<div>
// 第一行的下拉框表单
<div>
<Form.Item
name={`firstForm_${item.key}`}
label="水果"
rules={[{ required: true, message: '请选择'}]}
>
<Select
placeholder="请选择"
allowClear
>
<Option value="苹果" key="苹果">苹果</Option>
<Option value="桃子" key="桃子">桃子</Option>
<Option value="葡萄" key="葡萄">葡萄</Option>
</Select>
</Form.Item>
<Form.Item
name={`secondForm_${item.key}`}
label="动物"
rules={[{ required: true, message: '请选择'}]}
>
<Select
placeholder="请选择"
allowClear
mode="multiple"
>
<Option value="小狗" key="小狗">小狗</Option>
<Option value="大熊猫" key="大熊猫">大熊猫</Option>
<Option value="兔兔" key="兔兔">兔兔</Option>
</Select>
</Form.Item>
</div>
// 表格里面的表单
<div>
// 表头(自定义的,样式就不贴了,各位铁铁可以自行搞定呀)
<div>
<span>
姓名<span>|</span>
</span>
<span>
爱好<span>|</span>
</span>
<span>操作</span>
</div>
// 不固定数量的表单
{item.groupNum.map(o => {
return (
<Space
key={o.key}
style={{ display: 'flex', marginBottom: 8 }}
align="baseline"
>
<Form.Item
label=" "
name={`studentName_${item.key}_${o.key}`}
rules={[
{ required: true, message: "请输入"},
{ message: "请输入正确的值", pattern: /^[\u4e00-\u9fa5a-zA-Z0-9]+(\s+[\u4e00-\u9fa5a-zA-Z0-9]+)*$/ } // 可输入空格,但是首尾不能有空格
]}
>
<Input maxLength={10} placeholder="请输入"/>
</Form.Item>
<Form.Item
label=" "
name={`studentHobby_${item.key}_${o.key}`}
rules={[
{ required: true, message: "请输入"},
{ message: "请输入正确的值", pattern: new RegExp(/^(?![;\s])([\u4e00-\u9fa5\d\w;\s])*([\u4e00-\u9fa5\d\w\s]+)(?<![;\s])$/) } // 能输入空格且用分隔符隔开
]}
>
<Input placeholder="请输入,输入多个用分隔符;隔开"/>
</Form.Item>
<div>
<PlusCircleOutlined
style={{ fontSize: 16, color: '#255ff2' }}
onClick={() => addField(idx)}
/>
<MinusCircleOutlined
style={{ fontSize: 16, color: '#255ff2', paddingLeft: 10 }}
onClick={() => remove(item.key, o.key)}
/>
</div>
</Space>
)
})}
</div>
</div>
</Panel>
)
});
},[loading, treeInfo, panels]);
// 折叠面板的删除按钮
const getExtraBtn = item => (
<Button
type="text"
onClick={() => deletePanel(item)}
disabled={panels?.length === 1} //只有一个折叠面板时不可删除
>
Delete
<Button>
);
表单的回显(区分新增还是编辑):
useEffect(() => {
if (isType === 'edit') {
// 这里就根据你进这个页面拿到的数据进行渲染
// 我这里的panelLists是经过处理的,具体代码就不贴了,大家根据自己的项目进行处理
panelLists?.forEach(item => {
form.setFieldsValue({
[`firstForm_${item.key}`]: item.firstForm,
[`secondForm_${item.key}`]: item.secondForm,
});
item.groupNum?.forEach(o => {
form.setFieldsValue({
[`studentName_${item.key}_${o.key}`]: o.studentName,
[`studentHobby_${item.key}_${o.key}`]: o.studentHobby,
});
});
});
} else {
setPanels([
{
key: 0,
firstForm: '',
secondForm: '',
groupNum: [{ studentName: '', studentHobby: '', key: 0 }],
},
]);
}
}, []);
折叠面板的增减功能:
const [loading, setLoading] = useState(false);
const [panels, setPanels] = useState([]);
const [form] = Form.useForm();
// 新增折叠面板
const addFormList = () => {
// 深克隆一下数据
const list = cloneDeep(panels) || [];
const data = [
{
key: 0,
firstForm: '',
secondForm: [],
groupNum: [{ studentName: '', studentHobby: '', key: 0 }],
},
];
data[0].key = list[list?.length - 1]?.key + 1; // 动态改变key的值
// 删除一个折叠框,再新增时会保留上一次的数据,所以要清空表单
data.forEach(v => {
v.groupNum.forEach(vl => {
[`firstForm_${v.key}`]: '',
[`secondForm_${v.key}`]: [],
[`studentName_${v.key}_${vl.key}`]: '',
[`studentHobby_${v.key}_${vl.key}`]: '',
});
});
setPanels(list?.concat(data));
}
// 删除折叠面板
const deletePanel = (index) => {
const list = [...panels];
const newList = list.filter(i => i.key !== index);
setPanels([...newList]);
setLoading(!loading);
}
折叠面板里面的表单的增减功能:
// 添加表单
const addFields = () => {
const obj = panels?.map((v, i) => {
if (i === index) {
v.groupNum.push({
studentName: '',
studentHobby: '',
key: v.groupNum[v.groupNum?.length - 1].key + 1, // 用每次数组里面最后一个key加1
});
}
return v;
});
setPanels(obj);
setLoading(!loading);
};
// 删除表单
const remove = (idx, index) => {
const formValue = form.getFieldsValue();
const list = [...panels];
const result = list?.map(v => {
// 防止删除之后再新增时会保留上一次的数据
form.setFieldsValue({
...formValue,
[`studentName_${idx}_${index}`]: '',
[`studentHobby_${idx}_${index}`]: '',
});
// 只有一行表单时不能删除,并且在删除有数据的表单时要自动新增一行空白的表单
if (v.groupNum?.length > 1) {
if (v.key === idx) {
const groupNum = v.groupNum.filter(item => item.key !== index);
return { ...v, permission }
}
}
return v;
});
setPanels(result);
setLoading(!loading);
}
至此,结构的大致样式就完成了,至于传参和回显的逻辑涉及项目机密,就不公开了.......