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…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...