antd-tree异步加载+模糊搜索

实现树形组件 点击展开节点,动态加载数据,以及搜索

Demo

import { PageContainer } from '@ant-design/pro-components';
import { Input, Tree } from 'antd';
import { useRequest } from "ahooks"
import React, { useEffect, useMemo, useRef, useState } from 'react';

import { getTreeList, getChildrenNodes } from './mock'

interface DataNode {
  title: string;
  key: string;
  isLeaf?: boolean;
  children?: DataNode[];
}


const TreeDemo = () => {
  const [treeData, setTreeData] = useState([]);

  const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
  const [autoExpandParent, setAutoExpandParent] = useState(true);
  const onExpand = (newExpandedKeys: React.Key[]) => {
    setExpandedKeys(newExpandedKeys);
    setAutoExpandParent(false);
  };

  const [searchValue, setSearchValue] = useState('');

  // 格式化数据  
  const formatTreeData = useMemo(() => {
    return (data) => {
      if (data.length > 0) {
        return data.map((item) => {
          let titleDom = <span>{item?.name}</span>

          const strTitle = item.name;
          if (searchValue) {
            const index = strTitle.indexOf(searchValue);
            const beforeStr = strTitle.substring(0, index);
            const afterStr = strTitle.slice(index + searchValue.length);
            if (index > -1) {
              titleDom = (<span>
                {beforeStr}
                <span style={{ color: '#1890FF' }}>{searchValue}</span>
                {afterStr}
              </span>)
            }
          }


          if (item.children) {
            return {
              title: titleDom,
              key: item.code,
              children: formatTreeData(item.children),
              // isLeaf:false
            };
          }

          return {
            ...item,
            title: titleDom,
            key: item.code,
            // isLeaf: false
          };
        });
      }
    }
  }, [searchValue])

  // 加载列表接口
  const { loading, run: loadTreeData } = useRequest(getTreeList, {
    manual: true,
    onSuccess: (res) => {
      setTreeData(formatTreeData(res?.data))
    }
  })
  useEffect(() => {
    loadTreeData()
  }, [])

  const findExpandedKeys = (value, tree) => {
    let keys: any[] = [];
    for (let i = 0; i < tree.length; i++) {
      const node = tree[i];
      if (node.children) {
        if (node.children.some((item: { name: string }) => item.name?.includes(value))) {
          keys.push(node.parentCode, node.key)
        }
        keys = keys.concat(findExpandedKeys(value, node.children))
      }
    }
    return keys;
  }

  // 搜索框
  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { value } = e.target;
    const newExpandedKeys = findExpandedKeys(value, treeData)
    setExpandedKeys(newExpandedKeys);
    setSearchValue(value);
    // setAutoExpandParent(true);
  };

  const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => {
    // const children1== children.map((item) => {
    //   if (item.isLeaf) {
    //     item.children = []
    //   }
    //   return item
    // })
    return list.map((node) => {
      if (node.key === key) {
        return {
          ...node,
          children,
        };
      }
      if (node.children) {
        return {
          ...node,
          children: updateTreeData(node.children, key, children),
        };
      }
      return node;
    });
  }


  const onLoadData = async ({ key, children }: any) => {
    let result: any[];
    if (!children) {
      const res = await getChildrenNodes(key);
      result = formatTreeData(res?.data) || []
    }
    return new Promise<void>((resolve) => {
      if (children) {
        resolve();
        return;
      }
      setTimeout(() => {
        setTreeData((origin) =>
          updateTreeData(origin, key, result),
        );
        resolve();
      }, 1000);
    });
  }


  return (
    <PageContainer
      ghost
      header={{
        title: '树形控件',
      }}
    >
      <Input.Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChange} />
      <Tree
        treeData={formatTreeData(treeData)}
        loadData={onLoadData}
        onExpand={onExpand}
        expandedKeys={expandedKeys}
        autoExpandParent={autoExpandParent}
      />
    </PageContainer>
  );
};

export default TreeDemo;

mock.ts

import Mock from 'mockjs'
// 模拟 树列表
function getTreeList(): Promise<string> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(
                Mock.mock({
                    'data|3': [
                        {
                            'code|+1': ['1', '2', '3'],//+1 自增
                            'name|+1': [
                                '架构域1',
                                '架构域2',
                                '架构域3',
                            ],
                            'parentCode|+1': ['0', '0', '0']
                        }
                    ]
                })
            )
        }, 0)
    })
}


function getChildrenNodes(parentCode): Promise<string> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(
                Mock.mock({
                    'data|1-3': [
                        {
                            'code|+1': [
                                `${parentCode}-1`,
                                `${parentCode}-2`,
                                `${parentCode}-3`,
                            ],
                            'name|+1': [
                                `架构域${parentCode}-1`,
                                `架构域${parentCode}-2`,
                                `架构域${parentCode}-3`,
                            ],
                            parentCode: parentCode
                        }
                    ]
                })
            )
        }, 200)
    })
}

export { getTreeList, getChildrenNodes }

效果图

在这里插入图片描述

ps: 如果大佬有写过的,非常欢迎分享关于树形控件的

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值