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在字符串中的位置。

根据索引的结果,通过substringslice方法将字符串分割成前后两部分,然后构建一个新的title元素。如果搜索值在标题中存在,使用<span>元素将搜索值高亮显示;如果不存在,则直接使用原始的标题。

接着,判断item是否有子节点(item.children),如果有,则递归调用loop函数处理子节点,并将返回的结果作为children属性的值。

最后,在每个节点的处理中,都会返回一个包含titlekey属性的对象。

最外层的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/78614.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

了解Linux 的 mmap --- 笔记

学习这篇博客&#xff0c;进行了一些归纳Linux下mmap_linux mmap_一个山里的少年的博客-CSDN博客https://blog.csdn.net/qq_56999918/article/details/127070280 >>读取文件 读取文件方法&#xff1a;由操作系统提供的两个方法&#xff0c;read和write来读写文件。 由…

【SpringBoot】知识

.第一个程序HelloWorld 项目创建方式&#xff1a;使用 IDEA 直接创建项目 1、创建一个新项目 2、选择spring initalizr &#xff0c; 可以看到默认就是去官网的快速构建工具那里实现 3、填写项目信息 4、选择初始化的组件&#xff08;初学勾选 Web 即可&#xff09; 5、填…

flask中的应用上下文

flask中的应用上下文 Flask应用上下文主要包含两个对象&#xff1a;current_app和g。这两个对象在处理请求期间都是全局可访问的&#xff0c;但在每个请求结束时都会被重置。 current_app&#xff1a;这是当前激活的Flask应用的实例。在大多数情况下&#xff0c;你可以将其视为…

Git工具安装

Git 工具安装 1. 下载Git安装包2. 安装Git工具3. 简单的使用配置用户名 1. 下载Git安装包 打开官网 https://git-scm.com/downloads点击下载 2. 安装Git工具 右击以管理员身份运行 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9a99a73d54824800bc87db64f71f7602.png…

Vue3状态管理库Pinia——自定义持久化插件

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

Codejock Skin Framework Visual C++ MFC Crack

Codejock Skin Framework Visual C MFC Crack Codejock Visual CMFC皮肤框架为Windows开发人员提供了一种高度复杂的应用程序皮肤框架技术&#xff0c;该技术是在考虑Windows主题(视觉样式)的情况下开发的。只需几行代码就可以实现一个完全主题化的应用程序。 功能概述 Codejoc…

【雕爷学编程】MicroPython动手做(30)——物联网之Blynk 4

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

Element的Dialog+Form使用问题

在Element的Dialog中使用表单时&#xff0c;可能会出现以下问题 无法清空表单校验 <el-dialog title"新建资产" :visible.sync"addAssetsFormVisible" close"resetForm(addAssets)">resetForm (formName) {this.$refs[formName].resetFie…

2023-8-6 成年人交朋友,只筛选不改造。

前段时候&#xff0c;把Ex和相关的人都删掉了&#xff0c;又起了一次棺材。上次棺材给掀开&#xff0c;是因为肉桂拉小群又把我们拉一块。 我睡醒的时候看到了一堆的消息&#xff0c;他遇到麻烦想投靠我&#xff0c;还说以后要跟我混。他只有在遇到麻烦&#xff0c;遇到换工作…

前端CSS文字阴影text-shadow记录

前端CSS文字阴影text-shadow记录 一、文字阴影 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Doc…

【Redis】——AOF持久化

什么是AOF日志 AOF日志是redis为数据的持久化提供了的一个技术,日志里面记录着执行redis写命令。每当redis执行一条写命令的时候&#xff0c;就会将该命令记录 到AOF日志当中。当redis启动的时候&#xff0c;可以加载AOF日志中的所有指令&#xff0c;并执行这些指令恢复所有的…

Web3 solidity编写交易所合约 编写ETH和自定义代币存入逻辑 并带着大家手动测试

上文 Web3 叙述交易所授权置换概念 编写transferFrom与approve函数我们写完一个简单授权交易所的逻辑 但是并没有测试 其实也不是我不想 主要是 交易所也没实例化 现在也测试不了 我们先运行 ganache 启动一个虚拟的区块链环境 先发布 在终端执行 truffle migrate如果你跟着我…

使用WebMvcConfigurationSupport后导致原来返回的json数据变为了xml的解决方法

问题 未使用WebMvcConfigurationSupport拦截时返回的数据都是JSON格式&#xff0c;使用WebMvcConfigurationSupport做拦截后数据的返回变为了XML的格式。 原因 在Spring框架中&#xff0c;WebMvcConfigurationSupport 是一个类&#xff0c;它可以用于自定义Spring MVC的配置…

vue 标题文字字数过长超出部分用...代替 动态显示

效果: 浏览器最大化: 浏览器缩小: 代码: html: <div class"title overflow">{{item.name}}</div> <div class"content overflow">{{item.content}}</div> css: .overflow {/* 一定要加宽度 */width: 90%;/* 文字的大小 */he…

VB利用GDI+显示资源文件中的PNG文件

加载并打开资源文件&#xff0c;点击"添加自定义资源"&#xff0c;添加一个PNG文件&#xff0c;保存。 在代码编辑窗口复制粘贴以下代码,按F5运行后鼠标点击窗口即可显示资源文件中的PNG文件 Option Explicit Private Enum GpStatus Ok 0 GenericError 1 Invalid…

electron+vue+ts窗口间通信

文章目录 一. 目的二.逻辑分析三. 代码示例 "types/node": "^20.3.1","vitejs/plugin-vue": "^4.1.0","vueuse/electron": "^10.2.1","electron": "^25.2.0","electron-packager":…

DevOps在项目管理中的魔法:简化与深化

什么是DevOps&#xff1f; 定义与核心思想 DevOps, 这个名词&#xff0c;在技术领域中饱受瞩目。但它到底是什么&#xff1f;首先&#xff0c;DevOps并不仅仅是一个技术或者工具&#xff0c;它首先是一种文化&#xff0c;一种思想。DevOps是Development&#xff08;开发&#…

4,链表【p5】

链表 4.1哈希表简介4.2有序表简介4.3链表4.3.1例1-反转单向和双向链表4.3.2例2-打印两个有序链表的公共部分4.3.3面试时链表解题的方法论4.3.4例3-判断一个链表是否为回文结构4.3.4.1快慢指针 4.3.5例4-将单向链表按某值划分成左边小、中间相等、右边大的形式4.3.6例5-复制好友…

ORACLE和MYSQL区别

1&#xff0c;Oracle没有offet,limit&#xff0c;在mysql中我们用它们来控制显示的行数&#xff0c;最多的是分页了。oracle要分页的话&#xff0c;要换成rownum。 2&#xff0c;oracle建表时&#xff0c;没有auto_increment&#xff0c;所有要想让表的一个字段自增&#xff0c…

安装linux操作系统

安装虚拟机的步骤&#xff1a; 安装linux系统 之后开启虚拟机 之后重启&#xff0c;打开虚拟机&#xff0c;登录root账号