基于 antd design 组件库的动态表头封装

效果:

 

通过生成树形菜单控制表头动态显示

1)功能函数文件

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 文件代码

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 类型文件

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
};

时小记,终有成。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值