ant.design 组件库中的 Tree 组件实现可搜索的树: React+and+ts
ant.design 组件库中的 Tree 组件实现可搜索的树,在这里我会详细介绍每个方法,以及容易踩坑的点。
效果图:

首先是要导入的文件
// React 自带的属性
import React, { useMemo, useState } from 'react';
// antd 组件库中的,输入框和树形控件
import { Input, Tree } from 'antd';
// ts
import type { DataNode } from 'antd/es/tree';
下面是要渲染在 Tree 上的的数据,这是一个伪数据,如果你在开发时使用,直接修改给对应的变量名,赋值即可
const { Search } = Input;const x = 3;
const y = 2;
const z = 1;
const defaultData: DataNode[] = [];const generateData = (_level: number, _preKey?: React.Key, _tns?: DataNode[]) => {const preKey = _preKey || '0';const tns = _tns || defaultData;const children: React.Key[] = [];for (let i = 0; i < x; i++) {const key = `${preKey}-${i}`;tns.push({ title: key, key });if (i < y) {children.push(key);}}if (_level < 0) {return tns;}const level = _level - 1;children.forEach((key, index) => {tns[index].children = [];return generateData(level, key, tns[index].children);});
};
generateData(z);
这个方法是 Tree 组件提供的,用来筛选出要渲染的数据,筛选应该是优化一些性能的,因为在拿到接口数据时,每一项都可能会有很多的数据,而这一步是筛选出有用的值,过滤到其他,dataList 就是用来接收这个筛选后的数据的。
// 得到筛选后的值,根据当前要渲染的内容来筛选
const dataList: { key: React.Key; title: string }[] = [];// 将筛选后的值,赋给 dataList
const generateList = (data: DataNode[]) => {for (let i = 0; i < data.length; i++) {const node = data[i];const { key } = node;dataList.push({ key, title: key as string });if (node.children) {generateList(node.children);}}
};
generateList(defaultData);
触发了搜索后
触发了搜索后,会使用这个方法来对比两个参数key 和 tree,得到符合条件的值
key:当前搜索的值
tree:所有渲染的数据
const getParentKey = (key: React.Key, tree: DataNode[]): React.Key => {let parentKey: React.Key;for (let i = 0; i < tree.length; i++) {const node = tree[i];if (node.children) {if (node.children.some((item) => item.key === key)) {parentKey = node.key;} else if (getParentKey(key, node.children)) {parentKey = getParentKey(key, node.children);}}}return parentKey!;
};
现在进入进入组件内,处理逻辑,以下内容都包裹在 App组件中
const App: React.FC = () => {}export default App;
要使用到的可修改状态的值
expandedKeys :(受控)展开指定的树节点
searchValue : 在触发搜索时,存储当期输入的字段
autoExpandParent :是否自动展开父节点,所以它的默认值是布尔值
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);const [searchValue, setSearchValue] = useState('');const [autoExpandParent, setAutoExpandParent] = useState(true);
每次树状图变动,会更新 expandedKeys ,来做接下来的操作
onExpand :展开/收起节点时触发
const onExpand = (newExpandedKeys: React.Key[]) => {setExpandedKeys(newExpandedKeys);setAutoExpandParent(false);};
处理函数`onChange
下面这段代码是一个事件处理函数onChange,它接收一个React.ChangeEvent<HTMLInputElement>类型的事件对象作为参数。这个事件函数通常用于处理输入框的值变化事件。
在函数内部,首先通过解构赋值取出事件对象的value属性,即输入框的当前值。
然后,通过dataList数组的map方法遍历每个元素,并根据元素的title属性是否包含输入框的值来判断是否展开节点。如果包含,则调用getParentKey函数获取该节点的父节点的key,否则返回null。这个步骤用于更新展开的节点。
接下来,使用filter方法对newExpandedKeys数组进行过滤,去除其中的null值,并且去掉重复的元素,得到最终的展开节点数组newExpandedKeys。
调用setExpandedKeys函数将最终的展开节点数组更新到状态中。
接着,通过setSearchValue函数将输入框的值更新到状态中。
最后,调用setAutoExpandParent函数将autoExpandParent状态设置为true,表示父节点也会被自动展开。
这段代码的作用是实现一个用于过滤和展开树节点的搜索功能。当输入框的值发生变化时,根据输入的值进行过滤,找到匹配的节点,并展开它们的父节点,同时更新输入框的值和展开节点的状态。
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {const { value } = e.target;const newExpandedKeys = dataList.map((item) => {if (item.title.indexOf(value) > -1) {return getParentKey(item.key, defaultData);}return null;}).filter((item, i, self) => item && self.indexOf(item) === i);setExpandedKeys(newExpandedKeys as React.Key[]);setSearchValue(value);setAutoExpandParent(true);};
下面这段代码使用了useMemo钩子来创建一个名为treeData的变量。useMemo的作用是在依赖项(这里是searchValue)发生变化时执行内部的函数,并将函数的返回值作为treeData的值。
函数内部定义了一个名为loop的递归函数,用于遍历树形结构的数据data。
在loop函数中,首先将item.title转换为字符串类型,并使用indexOf方法查找searchValue在字符串中的位置。
根据索引的结果,通过substring和slice方法将字符串分割成前后两部分,然后构建一个新的title元素。如果搜索值在标题中存在,使用<span>元素将搜索值高亮显示;如果不存在,则直接使用原始的标题。
接着,判断item是否有子节点(item.children),如果有,则递归调用loop函数处理子节点,并将返回的结果作为children属性的值。
最后,在每个节点的处理中,都会返回一个包含title和key属性的对象。
最外层的useMemo的返回值就是使用loop函数处理defaultData得到的结果,它代表了树形结构数据经过搜索值过滤和处理后的新数据。
总而言之,这段代码的作用是根据搜索值searchValue对树形结构数据进行过滤,并对匹配的节点标题进行处理,添加搜索值的高亮显示。最后返回经过处理后的新的树形结构数据treeData。
const treeData = useMemo(() => {const loop = (data: DataNode[]): DataNode[] =>data.map((item) => {const strTitle = item.title as string;const index = strTitle.indexOf(searchValue);const beforeStr = strTitle.substring(0, index);const afterStr = strTitle.slice(index + searchValue.length);const title =index > -1 ? (<span>{beforeStr}<span className="site-tree-search-value">{searchValue}</span>{afterStr}</span>) : (<span>{strTitle}</span>);if (item.children) {return { title, key: item.key, children: loop(item.children) };}return {title,key: item.key,};});return loop(defaultData);}, [searchValue]);
组件的结构
最后就是组件的结构了,这段代码中使用了 Search 组件,通过 placeholder 属性设置了一个提示文本 Search ,并通过 onChange 属性指定了一个事件处理函数 onChange 来处理搜索框的值变化事件。这个 onChange 函数通常用于更新状态或执行其他逻辑,以响应搜索框中输入的值的变化。
总而言之,这段代码创建了一个包含搜索框和树形结构的组件,并将搜索框的值变化和树节点的展开或折叠事件与相应的事件处理函数关联起来。
return (<div><Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChange} /><TreeonExpand={onExpand}expandedKeys={expandedKeys}autoExpandParent={autoExpandParent}treeData={treeData}/></div>);
};
完整代码:
import React, { useMemo, useState } from 'react';
import { Input, Tree } from 'antd';
import type { DataNode } from 'antd/es/tree';const { Search } = Input;const x = 3;
const y = 2;
const z = 1;
const defaultData: DataNode[] = [];const generateData = (_level: number, _preKey?: React.Key, _tns?: DataNode[]) => {const preKey = _preKey || '0';const tns = _tns || defaultData;const children: React.Key[] = [];for (let i = 0; i < x; i++) {const key = `${preKey}-${i}`;tns.push({ title: key, key });if (i < y) {children.push(key);}}if (_level < 0) {return tns;}const level = _level - 1;children.forEach((key, index) => {tns[index].children = [];return generateData(level, key, tns[index].children);});
};
generateData(z);const dataList: { key: React.Key; title: string }[] = [];
const generateList = (data: DataNode[]) => {for (let i = 0; i < data.length; i++) {const node = data[i];const { key } = node;dataList.push({ key, title: key as string });if (node.children) {generateList(node.children);}}
};
generateList(defaultData);const getParentKey = (key: React.Key, tree: DataNode[]): React.Key => {let parentKey: React.Key;for (let i = 0; i < tree.length; i++) {const node = tree[i];if (node.children) {if (node.children.some((item) => item.key === key)) {parentKey = node.key;} else if (getParentKey(key, node.children)) {parentKey = getParentKey(key, node.children);}}}return parentKey!;
};const App: React.FC = () => {const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);const [searchValue, setSearchValue] = useState('');const [autoExpandParent, setAutoExpandParent] = useState(true);const onExpand = (newExpandedKeys: React.Key[]) => {setExpandedKeys(newExpandedKeys);setAutoExpandParent(false);};const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {const { value } = e.target;const newExpandedKeys = dataList.map((item) => {if (item.title.indexOf(value) > -1) {return getParentKey(item.key, defaultData);}return null;}).filter((item, i, self) => item && self.indexOf(item) === i);setExpandedKeys(newExpandedKeys as React.Key[]);setSearchValue(value);setAutoExpandParent(true);};const treeData = useMemo(() => {const loop = (data: DataNode[]): DataNode[] =>data.map((item) => {const strTitle = item.title as string;const index = strTitle.indexOf(searchValue);const beforeStr = strTitle.substring(0, index);const afterStr = strTitle.slice(index + searchValue.length);const title =index > -1 ? (<span>{beforeStr}<span className="site-tree-search-value">{searchValue}</span>{afterStr}</span>) : (<span>{strTitle}</span>);if (item.children) {return { title, key: item.key, children: loop(item.children) };}return {title,key: item.key,};});return loop(defaultData);}, [searchValue]);return (<div><Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChange} /><TreeonExpand={onExpand}expandedKeys={expandedKeys}autoExpandParent={autoExpandParent}treeData={treeData}/></div>);
};export default App;
官网地址: 树形控件 Tree - Ant Design
相关文章:
ant.design 组件库中的 Tree 组件实现可搜索的树: React+and+ts
ant.design 组件库中的 Tree 组件实现可搜索的树,在这里我会详细介绍每个方法,以及容易踩坑的点。 效果图: 首先是要导入的文件 // React 自带的属性 import React, { useMemo, useState } from react; // antd 组件库中的,输入…...
Linux系统编程之信号(上)
一、信号概念 信号就是软件中断。每当程序收到一个信号,都需要按指定的方法去处理。以下是UNIX系统的信号表。 其中core表示产生一个复制了该进程内存映像的core文件,它保存了程序现场,可以使用gdb来调试。 二、signal() signal()函数用于改…...
23.Netty源码之内置解码器
highlight: arduino-light Netty内置的解码器 在前两节课我们介绍了 TCP 拆包/粘包的问题,以及如何使用 Netty 实现自定义协议的编解码。可以看到,网络通信的底层实现,Netty 都已经帮我们封装好了,我们只需要扩展 ChannelHandler …...
sigmoid ReLU 等激活函数总结
sigmoid ReLU sigoid和ReLU对比 1.sigmoid有梯度消失问题:当sigmoid的输出非常接近0或者1时,区域的梯度几乎为0,而ReLU在正区间的梯度总为1。如果Sigmoid没有正确初始化,它可能在正区间得到几乎为0的梯度。使模型无法有效训练。 …...
RabbitMQ 消息队列
文章目录 🍰有几个原因可以解释为什么要选择 RabbitMQ:🥩mq之间的对比🌽RabbitMQ vs Apache Kafka🌽RabbitMQ vs ActiveMQ🌽RabbitMQ vs RocketMQ🌽RabbitMQ vs Redis 🥩linux docke…...
PHP实现在线进制转换器,10进制,2、4、8、16、32进制转换
1.接口文档 2.laravel实现代码 /*** 进制转换计算器* return \Illuminate\Http\JsonResponse*/public function binaryConvertCal(){$ten $this->request(ten);$two $this->request(two);$four $this->request(four);$eight $this->request(eight);$sixteen …...
报错 | Spring报错详解
Spring报错详解 一、前言二、报错提示三、分层解读1.最下面一层Caused by2.上一层Caused by3.最上层Caused by 四、总结五、解决方案 一、前言 本文主要是记录在初次学习Spring时遇到报错后的解读以及解决方案 二、报错提示 三、分层解读 遇到报错的时候,我们需要…...
PHP最简单自定义自己的框架数据库封装调用(五)
1、实现效果调用实现数据增删改查封装 2、index.php 入口定义数据库账号密码 <?php//定义当前请求模块 define("MODULE",index);//定义数据库 define(DB_HOST,localhost);//数据库地址 define(DB_DATABASE,aaa);//数据库 define(DB_USER,root);//数据库账号 def…...
使用Redis来实现点赞功能的基本思路
使用Redis来实现点赞功能是一种高效的选择,因为Redis是一个内存数据库,适用于处理高并发的数据操作。以下是一个基本的点赞功能在Redis中的设计示例: 假设我们有一个文章或帖子,用户可以对其进行点赞,取消点赞&#x…...
【黑马头条之app端文章搜索ES-MongoDB】
本笔记内容为黑马头条项目的app端文章搜索部分 目录 一、今日内容介绍 1、App端搜索-效果图 2、今日内容 二、搭建ElasticSearch环境 1、拉取镜像 2、创建容器 3、配置中文分词器 ik 4、使用postman测试 三、app端文章搜索 1、需求分析 2、思路分析 3、创建索引和…...
Nginx安装以及LVS-DR集群搭建
Nginx安装 1.环境准备 yum insatall -y make gcc gcc-c pcre-devel #pcre-devel -- pcre库 #安装openssl-devel yum install -y openssl-devel 2.tar安装包 3.解压软件包并创建软连接 tar -xf nginx-1.22.0.tar.gz -C /usr/local/ ln -s /usr/local/nginx-1.22.0/ /usr/local…...
后端开发9.商品类型模块
概述 简介 商品类型我设计的复杂了点,设计了多级类型 效果图 数据库设计...
spring框架自带的http工具RestTemplate用法
1. RestTemplate是什么? RestTemplate是由Spring框架提供的一个可用于应用中调用rest服务的类它简化了与http服务的通信方式。 RestTemplate是一个执行HTTP请求的同步阻塞式工具类,它仅仅只是在 HTTP 客户端库(例如 JDK HttpURLConnection&a…...
【flink】Checkpoint expired before completing.
使用flink同步数据出现错误Checkpoint expired before completing. 11:32:34,455 WARN org.apache.flink.runtime.checkpoint.CheckpointFailureManager [Checkpoint Timer] - Failed to trigger or complete checkpoint 4 for job 1b1d41031ea45d15bdb3324004c2d749. (2 con…...
【论文阅读】NoDoze:使用自动来源分类对抗威胁警报疲劳(NDSS-2019)
NODOZE: Combatting Threat Alert Fatigue with Automated Provenance Triage 伊利诺伊大学芝加哥分校 Hassan W U, Guo S, Li D, et al. Nodoze: Combatting threat alert fatigue with automated provenance triage[C]//network and distributed systems security symposium.…...
【ARM64 常见汇编指令学习 16 -- ARM64 SMC 指令】
文章目录 ARMv8 同步异常同步异常指令SMC TYPE 上篇文章:ARM64 常见汇编指令学习 15 – ARM64 标志位的学习 下篇文章:ARM64 常见汇编指令学习 17 – ARM64 BFI 指令 ARMv8 同步异常 在ARMv8架构中,同步异常主要包括以下几种: Un…...
uprobe trace多线程mutex等待耗时
问题背景环境 ubuntu2204 服务器支持debugfs uprobe,为了提升应用程序的性能,需要量化不同参数下多线程主程序等待在mutex上的耗时区别 linux document中对uprobe events的说明如下 uprobetracer.rst - Documentation/trace/uprobetracer.rst - Linux…...
Linux 和 MacOS 中的 profile 文件详解(一)
什么是 profile 文件? profile 文件是 Linux、MacOS 等(unix、类 unix 系统)系统中的一种配置文件,主要用于设置系统和用户的环境变量。 在 shell 中,可以通过执行 profile 文件来设置用户的环境变量。shell 有两种运…...
不用技术代码,如何制作成绩查询系统?
为了解决学校无力承担传统学生考试成绩查询平台的高昂费用,老师们可以考虑使用易查分这样的工具来免费制作一个学生考试成绩查询平台。易查分是一种简单易用的在线成绩查询系统,可以帮助老师们快速创建一个个性化的学生考试成绩查询平台。 使用易查分制作…...
flinksql sink to sr often fail because of nullpoint
flinksql or DS sink to starrocks often fail because of nullpoint flink sql 和 flink ds sink starrocks 经常报NullpointException重新编译代码 并上传到flink 集群 验证,有效 flink sql 和 flink ds sink starrocks 经常报NullpointException 使用flink-sta…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
