React antd 折叠面板里面包含表单的增减,折叠面板也有增减功能,以及记录这一块的传参和回显逻辑

页面样式如图:

一进这个抽屉页面就默认打开第一个折叠面板,点击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);
}

至此,结构的大致样式就完成了,至于传参和回显的逻辑涉及项目机密,就不公开了.......

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以帮你封装一个有增减功能折叠面板。首先需要安装ReactAntd,在命令行中输入以下命令: ``` npm install react antd ``` 然后你可以使用以下代码来实现一个简单的折叠面板: ```jsx import React, { useState } from 'react'; import { Collapse, Button } from 'antd'; const { Panel } = Collapse; const MyCollapse = () => { const [panels, setPanels] = useState(['1']); const addPanel = () => { const newKey = (parseInt(panels[panels.length - 1]) + 1).toString(); setPanels([...panels, newKey]); }; const removePanel = (key) => { const newPanels = panels.filter((panelKey) => panelKey !== key); setPanels(newPanels); }; return ( <> <Button onClick={addPanel}>Add Panel</Button> <Collapse accordion> {panels.map((key) => ( <Panel header={`Panel ${key}`} key={key}> <p>Content of panel {key}</p> <Button onClick={() => removePanel(key)}>Remove Panel</Button> </Panel> ))} </Collapse> </> ); }; export default MyCollapse; ``` 在这个例子中,我们使用了React的`useState` hook来管理折叠面板的状态。我们将`panels`数组作为状态,其中存储了所有折叠面板的key。然后我们定义了两个方法,`addPanel`和`removePanel`,分别用于添加和移除折叠面板。 在`addPanel`方法中,我们通过计算最后一个折叠面板的key来生成新的key,并使用`setPanels`方法将其添加到`panels`数组中。 在`removePanel`方法中,我们使用`filter`方法过滤出需要移除的折叠面板,并使用`setPanels`方法更新`panels`数组。 最后,在组件的渲染方法中,我们使用Antd的`Collapse`组件来渲染所有的折叠面板。我们还添加了一个`Button`组件,用于添加新的折叠面板。每个折叠面板中都有一个`Button`组件,用于移除该折叠面板。 希望这个例子能够帮助到你。如果你有任何问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值