在开发过程中,但是antd中的搜索会把多余的也会带出来

就例如下图,我们本想去搜索1但是他会把其子节点都带出来,其实我们的本意是像搜2一样或者当中间隔层处理



但是我们该如何解决这样的问题呢如何做到下面两种情况

(1)搜索过滤掉不匹配的内容只留下匹配的内容

这是没有搜索之前



这是搜索之后,当我们去搜索5的时候我们就会直接把213过滤掉



(2)搜索中当子节点不是搜索内容但是孙节点和祖孙节点中存在要搜索的内容要把该子节点进行保留

这是没有搜索之前



这是搜索之后,我们要保留的结果



那么主要方法如下,antd-treeselect中的filterTreeNode属性,是否根据输入项进行筛选,默认用 treeNodeFilterProp 的值作为要筛选的 TreeNode 的属性值



方法如下使用

//toLowerCase()的方法主要是为了使用不区分大小写使用
const filterTreeNode = (inputValue: string, treeNode: any) => {
return treeNode.title.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
}

接下来就是搜索功能的具体实现方法

 // 此处操作主要用于前端处理搜索树时过滤掉搜索出的父节点下与搜索内容无关的其他子节点
if (searchValue) {
const fileData = [...oldfileTree]//主要用于记录tree节点使用的 oldfileTree就是树的节点功能
// 用户树搜索的功能
const searchResult = getSearchList([...fileData], searchValue)
// 将树的列表更具搜索的内容的所有父级节点和搜索到内容id的合集
let parentKeys
if (name === 'apiManage') {
parentKeys = contents
.map((item: any) => {
if (item.searchTitle.toLowerCase().indexOf(searchValue.toLowerCase()) > -1) {
return getParentName(item.id, contents)
}
return null
})
.filter((item: any, i: any, self: any) => item && self.indexOf(item) === i)
} else {
parentKeys = contents
.map((item: any) => {
if (item.searchTitle.toLowerCase().indexOf(searchValue.toLowerCase()) > -1) {
return getParentKey(item.id, contents)
}
return null
})
.filter((item: any, i: any, self: any) => item && self.indexOf(item) === i)
}
//所有需要的id扁平化处理
const parentIdsList: any = parentKeys
.flat(2)
.filter((item: any, i: any, self: any) => item && self.indexOf(item) === i)
// 获取需要展开的id集合由于过程中可能存在层级丢失,需要使用traverseParent向上寻找所有父级的id序列
const getExpendKeys = parentIdsList
.map((item: string) => {
return traverseParent(searchResult, item)
})
.flat(2)
.filter((item: any, i: any, self: any) => item && self.indexOf(item) === i)
//设置翻开节点
setTreeExpandedKeys(getExpendKeys)
// 将搜索的集合转换成列表形式
generateList(searchResult)
// 把集合做转换成Map结构
const listMap = dataList.reduce((map, item: any) => {
map.set(item.id, item)
return map
}, new Map())
//将所有展开的key与集合使用Map快速匹配对应值并将Map中存在的标记为true
getExpendKeys.map((item: string) => {
if (listMap.has(item)) {
listMap.set(item, { ...listMap.get(item), hasSearch: true })
}
})
// 将搜索的结果和Map进行匹配,如果匹配成功则将该节点换成Map中该节点的内容
const result = hasTree(searchResult, listMap)
// 将融合好的hasSearch tree(是否是搜索的节点)进行去除所有false的节点
const filterTree = removeFalseNodes(result)
// 形成所有搜索的结果
setFileTree([...filterTree] as treeDataNode[])
}

getSearchList 就是用于搜索高亮使用的,hasSearch搜索到的值为true,搜索不到的值则为false

  const getSearchList = (data: treeDataNode[], searchValue: string) => {
const result: treeDataNode[] = data.map(item => {
const strTitle = item.searchTitle as string
const index = strTitle.toLowerCase().indexOf(searchValue.toLowerCase())
const beforeStr = strTitle.substring(0, index)
const afterStr = strTitle.slice(index + searchValue.length)
const regExp = new RegExp(searchValue, 'gi')
const matches = strTitle.match(regExp)
let value = ''
if (matches) {
strTitle.replace(regExp, (match: any) => {
value = match
return match
})
} const alias =
index > -1 ? (
<span>
{beforeStr}
<span className='site-tree-search-value'>{value}</span> //site-tree-search-value设置css样式,设置你需要的高亮的颜色什么颜色都可以
{afterStr}
</span>
) : (
<span>{strTitle}</span>
) if (item.children) {
return {
...item,
alias,
value: item.id,
hasSearch: index > -1 ? true : false, //将所有搜索结果是真的标记为true否则为false
children: getSearchList(item.children, searchValue)
}
}
return {
...item,
value: item.id,
hasSearch: index > -1 ? true : false, //将所有搜索结果是真的标记为true否则为false
alias
}
})
return result
}

getParentKey 的目的是找到给定 key 所对应的节点的直接父节点,并返回该父节点的 id 和 parentId。

getParentKey 函数没有明确处理未找到父节点的情况,可能会返回意外的结果或 undefined或者空数组。因而要使用.flat(2).filter((item: any, i: any, self: any) => item && self.indexOf(item) === i)来过滤

  const getParentKey = (key: React.Key, tree: any): React.Key => {
let parentKey: any
for (let i = 0; i < tree.length; i++) {
const node = tree[i]
if (node.children) {
if (node.children.some((item: any) => item.id === key)) {
parentKey = [node.id, node.parentId]
} else if (getParentKey(key, node.children)) {
parentKey = [getParentKey(key, node.children), node.parentId]
}
}
}
return parentKey
}

traverseParent 的目的是递归地查找给定 parentId 的所有祖先节点,并将它们的 id 收集到一个数组中。

traverseParent 在未找到指定 parentId 的情况下会返回一个空数组。因而要使用.flat(2).filter((item: any, i: any, self: any) => item && self.indexOf(item) === i)来过滤

  const traverseParent = (treeData: treeDataNode[], parentId?: string) => {
let result: string[] = []
function traverse(nodes: treeDataNode[], parentId: string) {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (node.id === parentId) {
result = [...result, node.id]
if (node.parentId) {
traverse(treeData, node.parentId)
}
break
} else if (node.children) {
traverse(node.children, parentId)
}
}
}
if (parentId) traverse(treeData, parentId) return result
}

generateList 的目的是用于扁平化树形数据结构并转换每个节点的格式

 const dataList: { key: React.Key; title: string; name: string }[] = []
const generateList = (data: treeDataNode[]) => {
for (let i = 0; i < data.length; i++) {
const node = data[i]
dataList.push({ ...node, name: node.title })
if (node.children) {
generateList(node.children)
}
}
}

hasTree 就是将树重新构建,将树中存在的与Map结构中同样内容的值换成Map结构的信息

  const hasTree = (tree: treeDataNode[], map: any) => {
return tree.map(node => {
if (map.has(node.id)) {
node = map.get(node.id)
}
// 如果节点有子节点,递归处理子节点
if (node.children && node.children.length > 0) {
node.children = hasTree(node.children, map)
}
return node
})
}

removeFalseNodes 是删除hasSearch 为false的置换成undefined在将其过滤掉最后剩下的就是搜索出的结果

const removeFalseNodes = (data: treeDataNode[]) => {
return data
.map(item => {
// 递归处理children数组
item.children = item.children && item.children.filter(child => child.hasSearch)
if (item.children && item.children.length > 0) {
removeFalseNodes(item.children)
}
// 如果当前对象的hasSearch为false且children为空数组,则返回undefined以从结果中排除
return item.hasSearch || (item.children && item.children.length > 0) ? item : undefined
})
.filter(item => item !== undefined)
}

总之,在一些时候搜索为了迎合需要不得不这么操作,那么该操作结合了antd官方的搜索操作,在此之前需要保持清醒的头脑

首先我们搜索出来高亮这个操作antd TreeSelect的是可以实现,但是搜索中我们发现实现不了搜索过滤,但是又要解决这个问题,想尝试使用数组方法将不是的部分删除,只能解决节点是的情况,当出现差层,何为差层就是当子节点不是搜索内容但是孙节点和祖孙节点中存在要搜索的内容要把该子节点进行保留的时候发现数据保留不住,不知道该如何解决,翻阅了ES6后发现使用Map做一层数据存储,并结合搜索情况将所有搜索的父节点向上遍历将其hasSearch设置为true,这样在重新构建树的时候可以将所有需要的节点变成true,再最后将所有节点是false的节点进行删除,只保留hasSearch为true的节点。总之该操作中使用了数组的方法,以及ES6的Map结构,当做出来的时候感觉雨过天晴,但是个人觉得这些还是太冗余了,之后会更进方法,如果大家有什么更好的方法请多指教 (´・Д・)」

最后就是如果这种问题可以放在后端在搜索的时候进行请求来减少前端遍历和重组的过程减少渲染次数会更好

Antd-React-TreeSelect前端搜索过滤的更多相关文章

  1. Mock平台3-初识Antd React 开箱即用中台前端框架

    微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 内容提要 首先说下为啥这次测试开发系列教程前端选择Antd React,其实也是纠结对比过最终决定挑战一把,想法大概有几下几点: 笔者自己 ...

  2. DRF框架(八)——drf-jwt手动签发与校验、搜索过滤组件、排序过滤组件、基础分页组件

    自定义drf-jwt手动签发和校验 签发token源码入口 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口,不然进不了登录页面 获取提交的username ...

  3. antd+react项目迁移vite的解决方案

    antd+react+webpack往往是以react技术栈为主的前端项目的标准组合,三者都有成熟的生态和稳定的表现,但随着前端圈的技术不断革新,号称下一代构建平台vite2的发布,webpack似乎 ...

  4. 从0开始用webpack开发antd,react组件库npm包并发布

    一.初始化一个npm包 1.新建一个文件夹(名称随意,建议和报名一致),输入命令 :npm init -y 会自动生成一个包的说明文件 package.json如下(本文以scroll-antd-ta ...

  5. js实现table中前端搜索(模糊查询)

    项目中用到js前端搜索功能,根据 姓名或姓名 进行 搜索,实现方法如下,遍历table所有行中的某列,符合条件则置tr为display:'',不满足条件置tr为display:none. 代码如下: ...

  6. vuejs 1.x - 实例:搜索过滤

    <!DOCTYPE html> <html> <head> <meta name="viewport" content="wid ...

  7. 基于React 的前端UI开发框架 及与Electron 的结合 https://cxjs.io/

    1.cxjs  基于React 的前端UI开发框架    https://cxjs.io/ coreu   http://coreui.io/ 2.antd-admin                ...

  8. bootstrap table 前端搜索

    1.bootstrap-table对于前端的搜索可以通过官网设置,但发现前端搜索出现bug,网上找到一个bootstrap-table的扩充js  bootstrap-table-mytoolbar. ...

  9. 利用css实现搜索过滤

    无意中找到一种利用css就可实现的搜索过滤的方法,不得不说看了代码之后确实被惊艳到了,亏我之前面试还因为做这个功能做太慢而拖了后腿.在此记录下代码: <!DOCTYPE html> < ...

  10. jQuery实现简单前端搜索功能

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. dense并行训练1-流水线并行

    并行训练-流水线 简述 并行训练主要有三种策略: 数据并行训练加速比最高,但要求每个设备上都备份一份模型,显存占用比较高,但缺点是通信量大. 张量并行,通信量比较高,适合在机器内做模型并行. 流水线并 ...

  2. Ubuntu 18.04安装xdrp以使用远程桌面

    背景 开发环境有一台服务器默认没有屏幕(被我拿走用来拓展屏幕了),有时候需要使用到界面但嫌弃拆显示器太麻烦,因此使用远程桌面来解决这个需求. 做法 安装xrdp sudo apt install -y ...

  3. Docker部署php运行环境

    编写docker-compose.yml配置文件,使用nginx作为web服务器,转发php的请求. version: "3" services: web: image: ngin ...

  4. 一文搞懂到底什么是 AQS

    前言 日常开发中,我们经常使用锁或者其他同步器来控制并发,那么它们的基础框架是什么呢?如何实现的同步功能呢?本文将详细讲解构建锁和同步器的基础框架--AQS,并根据源码分析其原理. 一.什么是 AQS ...

  5. AT_abc215F 题解

    考虑二分答案. 假设当前二分的答案为 \(k\),那么对于每个点,距离大于等于 \(k\) 的点构成了平面上 \(4\) 个子平面. 那么只需查询子平面中是否存在点即可,类似于窗口的星星,把问题转换成 ...

  6. Spring手动获取bean的四种方式

    一.实现BeanFactoryPostProcessor接口 @Component public class SpringUtil implements BeanFactoryPostProcesso ...

  7. 为什么js中要用new?

    你new的不是对象,是构造函数,new + 构造函数生成对象.如果单就调用方法而言,确实不必用new.new一般用在"js使用原型和this关键字实现面向对象"的过程中. 大多数情 ...

  8. 深度学习pytorch常用操作以及流程

    在微信公众号上看到这篇文章,担心以后想找的时候迷路,所以记录到了自己的博客上,侵扰致歉,随时联系可删除. 1.基本张量操作 1. 1 创建张量 介绍: torch.tensor() 是 PyTorch ...

  9. 松灵机器人scout mini小车 自主导航(3)——建图导航仿真

    松灵机器人Scout mini小车建图导航仿真 在之前的文章中,我们已经介绍了如何在gazebo和rviz对scout mini小车进行仿真,并且测试了添加自定义的传感器,在本文章中将进一步介绍如何利 ...

  10. Linux 中 WIFI 和热点的使用

    之前一直在 ubuntu 的图形界面中使用,突然需要在 ARM 板上打开热点,一时给弄蒙了,在此记录一下 一.网卡命令 显示所有网络信息 sudo ip link show 关闭或打开网络 sudo ...