antd实现多个Tree点击任一 Tree 组件的叶子节点后,其他所有 Tree 组件的节点选中状态都被清除

285 阅读2分钟

需求

antd多个Tree实现点击一个 Tree 组件的叶子节点后,其他所有 Tree 组件的节点选中状态都被清除

思路

  1. Tree组件的选中状态可以由selectedKeys属性控制,这是核心
  2. 其他所有 Tree 组件的节点选中状态都被清除,那么如何判断当前选中的是哪个Tree是关键

实现

  1. 创建 currentSelectedKeys:这个状态用于记录当前选中的节点的 key 值。每当点击一个叶子节点时,我们会将当前节点的 key 值记录在这个状态中,以便在每个 Tree 组件的 selectedKeys 属性中正确设置选中状态。这样做可以确保只有一个 Tree 组件的节点处于选中状态。
  2. 创建activeTreeIndex:这个状态用于记录当前活动的 Tree 组件的索引。每当点击一个 Tree 的节点时,我们会根据点击的节点信息确定当前活动的 Tree 组件的索引,以便后续在设置选中状态时只对当前活动的 Tree 组件进行操作,从而避免干扰其他 Tree 组件的状态。
  3. 当触发onSelect事件后,首先根据点击的节点信息找到当前活动的 Tree 组件的索引,并将其记录在 activeTreeIndex 中。然后,我们判断点击的节点是否是叶子节点,如果是叶子节点,则将当前节点的 key 值记录在 currentSelectedKeys 中。

这样,在每个 Tree 组件的 selectedKeys 属性中,我们根据 activeTreeIndex 来判断是否应该设置选中状态。只有当前活动的 Tree 组件的节点会显示选中状态,其他 Tree 组件会被清除选中状态,从而实现需求。

组件代码

import { Tree } from 'antd';
import type { TreeProps } from 'antd/es/tree';
import React from 'react';
import styles from './index.less';
import './antd.less';
import { Key } from 'rc-tree/lib/interface';

interface IProps {
  title?: string;
  children?: React.ReactNode;
  onSelect: (selectedKeys: Key[], info: object, el?: object) => void;
  treeData?: any[];
  treeDataArr?: any[];
}

const DatasourceTree: React.FC<IProps> = (props) => {
  const { children, title, onSelect, treeData, treeDataArr } = props;
  const [currentSelectedKeys, setCurrentSelectedKeys] = React.useState<React.Key[]>([]);
  const [activeTreeIndex, setActiveTreeIndex] = React.useState<number | null>(null);

  const handleSelect: TreeProps['onSelect'] = (selectedKeys: React.Key[], info: any) => {
    const selectedNode = info.node;
    if (!selectedNode.children || selectedNode.children.length) {
      onSelect(selectedKeys, info);
    }
  };

  const handleSelect2: any = (selectedKeys: React.Key[], info: any, el: any) => {
    setActiveTreeIndex((treeDataArr as any[]).findIndex((item: any) => item === el));
    const selectedNode = info.node;
    if (!selectedNode.children || !selectedNode.children.length) {
      setCurrentSelectedKeys(selectedKeys);
      onSelect(selectedKeys, info, el);
    }
  };

  const { TreeNode } = Tree
  const renderTreeNodes = (data: any) => {
    return data.map((item: any) => {
      if (item.children.length) {
        return (
          <TreeNode title={item.name} key={item.id} selectable={false}>
            {renderTreeNodes(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode title={item.name} key={item.id} />;
    });
  };

  return (
    <div className={styles.treeLayoutContainer}>
      <div className={styles.treeContainer}>
        {treeData && treeData.length && !treeDataArr ? (
          <>
            <div className={styles.treeTitle}>{title}</div>
            <Tree
              defaultExpandAll
              onSelect={handleSelect}
            >
              {renderTreeNodes(treeData)}
            </Tree>
          </>
        ) : null}
        {!treeData && treeDataArr && treeDataArr.length &&
          treeDataArr.map((el: any, index: number) => (
            <div key={index}>
              <div className={styles.treeTitle}>{el.title}</div>
              <Tree
                defaultExpandAll
                onSelect={(selectedKeys: Key[], info: any) => handleSelect2(selectedKeys, info, el)}
                selectedKeys={index === activeTreeIndex ? currentSelectedKeys : []}
              >
                {renderTreeNodes(el.treeData)}
              </Tree>
            </div>
          ))
        }
      </div>
      <div style={{ width: '100%', marginLeft: '16px' }}>{children}</div>
    </div>
  );
};

DatasourceTree.defaultProps = {
  title: '数据源管理',
};

export default DatasourceTree;