Antd - Table 父子表格Checkbox联动

Antd - Table 父子表格Checkbox联动

前言

由于Antd中的父子组件之间,如果有多选功能,那么不会有联动的关系,需要自己实现。

一. 勾选父子组件联动

代码如下:

import React, { useState } from 'react';
import { Table } from 'antd';
const Column = Table.Column;
interface Parent {
    parentId: number;
    name: string;
    orderID: number;
    childList: Children[]
}
interface Children {
    name: string;
    childId: number;
}
const dataSource: Parent[] = [
    { parentId: 1, name: '张三', orderID: 123456, childList: [{ name: '吹风机', childId: 1001, }, { name: '牛奶', childId: 1002, }] },
    { parentId: 2, name: '李四', orderID: 987654, childList: [{ name: '鼠标', childId: 1003, }, { name: '键盘', childId: 1004, }] }
]
const Page = () => {
    const [parentSelectedRowKeys, setParentSelectedRowKeys] = useState<number[]>([])
    const [childSelectedRowKeys, setChildSelectedRowKeys] = useState<number[]>([])


    const onParentSelectChange = (record: Parent, selected: boolean) => {
        // 目前为止选择的父节点和子节点的RowKey
        const preParentRowKeys: number[] = [...(parentSelectedRowKeys || [])];
        let preChildRowKeys: number[] = [...(childSelectedRowKeys || [])];
        // 当前勾选的父节点,其对应的所有子节点的RowKey
        let currentChildRowKeys = dataSource.find(parent => parent.parentId === record.parentId)?.childList.map(item => item.childId) || [];
        // 判断是否选中,选中就加入,否则从老的RowKey中删除它(去重)
        if (selected) {
            preParentRowKeys.push(record.parentId)
            preChildRowKeys = Array.from(new Set([...currentChildRowKeys, ...preChildRowKeys]))
        } else {
            // 否则,父节点取消选中,子节点全部取消
            preParentRowKeys.splice(preParentRowKeys.findIndex(parentRowKey => parentRowKey === record.parentId), 1)
            preChildRowKeys = preChildRowKeys.filter(childRowKey => !currentChildRowKeys.some(rowkey => rowkey === childRowKey))
        }
        // 最后重新设置父,子的SelectedRowKeys
        setParentSelectedRowKeys(preParentRowKeys)
        setChildSelectedRowKeys(preChildRowKeys)
    }
    // 父节点选中全部
    const onParentSelectAll = (selected: true, selectedRows: Parent[], changeRows: Parent[]) => {
        let preParentRowKeys = [...(parentSelectedRowKeys || [])];
        let currentChildRowKeys: number[] = [];
        changeRows.forEach(e => {
            currentChildRowKeys = [...currentChildRowKeys, ...e.childList.map(child => child.childId)]
        });
        // 如果选中,那么所有子节点全部选中
        if (selected) {
            preParentRowKeys = Array.from(new Set([...preParentRowKeys, ...changeRows.map(item => item.parentId)]))
            setChildSelectedRowKeys(currentChildRowKeys)
        } else {
            // 否则所有子节点取消选中
            preParentRowKeys = preParentRowKeys.filter(item => !changeRows.some(e => e.parentId === item))
            setChildSelectedRowKeys([])
        }
        // 设置父节点RowKey
        setParentSelectedRowKeys(preParentRowKeys)
    }

    const parentRowSelection = {
        selectedRowKeys: parentSelectedRowKeys,
        onSelect: onParentSelectChange,
        onSelectAll: onParentSelectAll,
    }

    const onChildSelectChange = (record: Children, selected: true, selectedRows: Children[]) => {
        const preChildRowKeys: number[] = [...(childSelectedRowKeys || [])];
        // 判断当前子节点是 取消勾选/勾选 状态,对应维护
        if (selected) {
            preChildRowKeys.push(record.childId)
        } else {
            preChildRowKeys.splice(preChildRowKeys.findIndex(item => item === record.childId), 1)
        }
        selectedRows = selectedRows.filter(a => a)
        // 判断子节点选中的个数,和对应当前的父节点下的子节点个数是否相等,如果是,那么对应父节点也要勾选上
        for (const item of dataSource) {
            if (item.childList.find(d => d.childId === record.childId)) {
                const preParentRowKeys: number[] = [...(parentSelectedRowKeys || [])];
                if (item.childList.length === selectedRows.length) {
                    preParentRowKeys.push(item.parentId)
                } else {
                    if (preParentRowKeys.find(rowkey => rowkey === item.parentId)) {
                        preParentRowKeys.splice(preParentRowKeys.findIndex(rowkey => rowkey === item.parentId), 1)
                    }
                }
                setParentSelectedRowKeys(preParentRowKeys)
                break;
            }
        }
        setChildSelectedRowKeys(preChildRowKeys)
    }
    const onChildSelectAll = (selected: true, selectedRows: Children[], changeRows: Children[]) => {
        let preChildRowKeys: number[] = [...(childSelectedRowKeys || [])];
        if (selected) {
            preChildRowKeys = Array.from(new Set([...preChildRowKeys, ...changeRows.map(item => item.childId)]))
        } else {
            preChildRowKeys = preChildRowKeys.filter(item => !changeRows.some(child => child.childId === item))
        }
        // 子节点全部选中或者取消全部选中,那么对应父节点的状态也要勾选或者取消勾选
        for (const item of dataSource) {
            if (item.childList.find(d => d.childId === changeRows[0].childId)) {
                const preParentRowKeys: number[] = [...(parentSelectedRowKeys || [])];
                if (selected) {
                    //全选
                    preParentRowKeys.push(item.parentId)
                } else {
                    //取消全选
                    preParentRowKeys.splice(preParentRowKeys.findIndex(rowkey => rowkey === item.parentId), 1)
                }
                setParentSelectedRowKeys(preParentRowKeys)
                break;
            }
        }
        setChildSelectedRowKeys(preChildRowKeys)
    }

    const childRowSelection = {
        selectedRowKeys: childSelectedRowKeys,
        onSelect: onChildSelectChange,
        onSelectAll: onChildSelectAll
    }

    const expandedRowRender = (record: Parent) => {
        const { childList } = record;
        return <Table dataSource={childList} rowKey={'childId'} rowSelection={childRowSelection} pagination={false}>
            <Column key={'childId'} dataIndex={'childId'} title={'childId'} />
            <Column key={'name'} dataIndex={'name'} title={'购买产品'} />
        </Table>
    }

    return <>
        <Table dataSource={dataSource} rowKey={'parentId'} expandable={{ expandedRowRender }} rowSelection={parentRowSelection} pagination={false}>
            <Column key={'parentId'} dataIndex={'parentId'} title={'ID'} />
            <Column key={'name'} dataIndex={'name'} title={'姓名'} />
            <Column key={'orderID'} dataIndex={'orderID'} title={'订单号'} />
        </Table>
    </>
}

export default Page;

注意:

  1. 可以选择Redux去存储父子组件对应的RowKey,否则就要在同一个组件中维护状态。
  2. 建议把类型定义描述好,否则父子组件联动很容易出现问题,不要总是写any,否则很难维护的。

二. 效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值