效果:
通过生成树形菜单控制表头动态显示
1)功能函数文件
javascript
import { TreeDataNode } from "antd";
import { ColumnsDataType } from "./type";
/**
* 过滤表格头数据到 tree 组件 并且过滤掉不需要在 tree 组件需要展示的节点
* @param { Array<ColumnsDataType> } columnsInfo 表头原始数据
* @param { string[] } nodesOnTheTreeAreNotDisplayed 不需要展示的节点 key
* @param { string[] } needDisabledItem 需要禁用掉的元素
* @return { TreeDataNode[] }
*/
export const filterTableColumnsToTree = (
columnsInfo: Array<ColumnsDataType>,
nodesOnTheTreeAreNotDisplayed: string[],
needDisabledItem: string[]
): TreeDataNode[] => {
return columnsInfo.reduce((acc, item) => {
if (!nodesOnTheTreeAreNotDisplayed.includes(item.key)) {
let newItem: TreeDataNode = { key: item.key, title: item.title };
if (needDisabledItem.includes(String(newItem.key))) {
newItem.disabled = true;
}
if (item.children && item.children.length > 0) {
const filteredChildren = filterTableColumnsToTree(
item.children,
nodesOnTheTreeAreNotDisplayed,
needDisabledItem
);
if (filteredChildren.length > 0) {
newItem.children = filteredChildren;
}
}
acc.push(newItem);
}
return acc;
}, [] as TreeDataNode[]);
};
/**
* 判断树节点是否已经被选中,添加 hidden 属性为真显示对应表头
* @param { React.Key[] } currentCheckTreeKeys 当前被选中的树节点 key
* @param { ColumnsDataType[] } originalTableColumns 原先的表头数据
* @param { React.Key[] } nodesOnTheTreeAreNotDisplayed 不需要在 tree 组件中进行操作的节点数据
* @return { ColumnsDataType[] } 重新添加过 hidden 属性的表头数据
*/
export const filterTheHeadDataAccordingToTheTreeNode = (
currentCheckTreeKeys: React.Key[],
originalTableColumns: ColumnsDataType[],
nodesOnTheTreeAreNotDisplayed: React.Key[]
): ColumnsDataType[] => {
const updatedColumns = originalTableColumns.map((category) => {
// 如果节点没有子节点,则根据当前节点的选中状态来显示或隐藏对应的表头
if (!category.children || category.children.length === 0) {
category.hidden = !currentCheckTreeKeys.includes(category.key);
} else {
// 检查是否为需要默认显示的节点,如果是,则将其 hidden 属性设置为 false
if (nodesOnTheTreeAreNotDisplayed.includes(category.key)) {
category.hidden = false;
}
// 如果该节点有子节点,递归处理子节点
category.children = processChildren(
category.children,
currentCheckTreeKeys
);
// 通过子节点的 hidden 状态决定父节点的 hidden 状态
category.hidden = category.children.every((child) => child.hidden);
}
return category;
});
return updatedColumns;
};
/**
* 递归处理所有层级的 children,并根据需要添加父级及其所有子级到表头
* @param { ColumnsDataType[] } children 表头子节点数组
* @param { React.Key[] } currentCheckTreeKeys 当前被选中的树节点的 key 数组
* @return { ColumnsDataType[] } 处理后的表头子节点数组
*/
const processChildren = (
children: ColumnsDataType[],
currentCheckTreeKeys: React.Key[]
): ColumnsDataType[] => {
return children.map((child) => {
// 如果子节点还有自己的 children,递归处理
if (child.children && child.children.length > 0) {
child.children = processChildren(child.children, currentCheckTreeKeys);
// 通过子节点的 hidden 状态决定父节点的 hidden 状态
child.hidden = child.children.every((ch) => ch.hidden);
} else {
// 没有更深层次的 children,直接根据当前节点的选中状态更新 hidden
child.hidden = !currentCheckTreeKeys.includes(child.key);
}
return child;
});
};
2)index.tsx 文件代码
javascript
import { SettingOutlined } from "@ant-design/icons";
import { Popover, Tree } from "antd";
import { useEffect, useState } from "react";
import {
filterTableColumnsToTree,
filterTheHeadDataAccordingToTheTreeNode,
} from "./function";
import { TreeComponentType } from "./type";
const DynamicTableHeader = ({
treeDataInfo,
updataColumns,
defaultSelected,
needDisabledItem,
nodesOnTheTreeAreNotDisplayed,
getNewColumns,
}: TreeComponentType) => {
//
// 当前选中的所有 key
const [checkValue, setCheckValue] = useState<React.Key[]>(
defaultSelected ?? []
);
/**
* tree 组件勾选复选框事件
* @param { React.Key[] } value 获取到勾选的 key
* @return { void }
*/
const treeCheck = (value: React.Key[]): void => {
setCheckValue(value);
};
/**
* tree 组件点击文字选择
* @param { React.Key[] } selectedKeysValue 点击文字获取到对应的 key
* @return { void }
*/
const treeSelect = (selectedKeysValue: React.Key[]): void => {
let copyCheckedKeys = [...checkValue];
if (!checkValue.includes(selectedKeysValue[0])) {
copyCheckedKeys.push(selectedKeysValue[0]);
setCheckValue(copyCheckedKeys);
} else {
copyCheckedKeys.splice(copyCheckedKeys.indexOf(selectedKeysValue[0]), 1);
setCheckValue(copyCheckedKeys);
}
};
useEffect(() => {
let newColumns = filterTheHeadDataAccordingToTheTreeNode(
checkValue,
treeDataInfo,
nodesOnTheTreeAreNotDisplayed ?? []
);
getNewColumns(newColumns);
}, [updataColumns, checkValue]);
useEffect(() => {
setCheckValue(defaultSelected);
}, [updataColumns]);
const treeComponent = (
<Tree
checkable
selectable={false}
checkedKeys={checkValue}
defaultExpandedKeys={defaultSelected}
onCheck={treeCheck as any}
onSelect={treeSelect}
treeData={filterTableColumnsToTree(
treeDataInfo,
nodesOnTheTreeAreNotDisplayed ?? [],
needDisabledItem
)}
/>
);
return (
<Popover
content={
<div
style={{
width: 250,
height: 250,
overflow: "scroll",
marginTop: "20px",
}}
>
{treeComponent}
</div>
}
title="........"
>
<SettingOutlined style={{ fontSize: "16px", color: "#3A5E99" }} />
</Popover>
);
};
export default DynamicTableHeader;
3)TS 类型文件
javascript
export type ColumnsDataType = {
key: string;
title: string;
dataIndex: string;
hidden: boolean;
align?: string;
fixed?: string;
ellipsis?: {
showTitle?: boolean;
};
width?: number;
height?: number;
children?: ColumnsDataType[];
render?: (params1: string, record: any) => void;
renderFormItem?: any;
};
export type TreeComponentType = {
needDisabledItem: string[];
updataColumns: number; // 需要操作表格内部数据单并非弹框处理 【 恢复表头到未操作之前 】
defaultSelected: React.Key[]; // 需要默认选中的树节点
treeDataInfo: TableColumnsType<ColumnsDataType>; // 表格头的原始数据信息
nodesOnTheTreeAreNotDisplayed?: string[]; // 不需要在树形组件中显示的节点
getNewColumns: (params: ColumnsDataType[]) => void; // 获取新生成的表头 columns
};
时小记,终有成。