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;
注意:
- 可以选择
Redux
去存储父子组件对应的RowKey
,否则就要在同一个组件中维护状态。 - 建议把类型定义描述好,否则父子组件联动很容易出现问题,不要总是写
any
,否则很难维护的。