前言:
antd Tree组件带搜索,官网示例感觉很麻烦,不容易让人懂,我就自己实现了一个。
实现代码:
一、这个是搜索到后,包含字符标红
import React, { Component } from 'react';
import { Form, Input, Tree } from 'antd';
const TreeNode=Tree.TreeNode;
const { Search } = Input;
const treeData = [
{
title: '0-0',
key: '0-0',
children: [
{
title: '0-0-0',
key: '0-0-0',
children: [
{ title: '0-0-0-0-88', key: '0-0-0-0' },
{ title: '0-0-0-1', key: '0-0-0-1' },
{ title: '0-0-0-2', key: '0-0-0-2' },
],
},
{
title: '0-0-1',
key: '0-0-1',
children: [
{ title: '0-0-1-0', key: '0-0-1-0' },
{ title: '0-0-1-1', key: '0-0-1-1' },
{ title: '0-0-1-2', key: '0-0-1-2' },
],
},
{
title: '0-0-2',
key: '0-0-2',
},
],
},
{
title: '99',
key: '0-1',
children: [
{ title: '0-1-0-0', key: '0-1-0-0' },
{ title: '9988', key: '0-1-0-1' },
{ title: '0-1-0-2-99988', key: '0-1-0-2' },
],
},
{
title: '0-2',
key: '0-2',
},
];
class Index extends Component {
formRef = React.createRef();
constructor(props) {
super(props);
this.state = {
expandedKeys: [],//树节点展开key
treeData: [],
copyTree: [],//备份 treeData
copyExpandedKeys: [], //备份 展开key
searchValue: ""
}
}
componentDidMount() {
let a = this.expandedKeysFun(treeData); //展开key
let cp = JSON.stringify(treeData); //这个是最简单的 深拷贝
this.setState({
treeData: treeData,
expandedKeys: a,
copyTree: cp,
copyExpandedKeys: a
})
}
arrayTreeFilter = (data, predicate, filterText) => {
const nodes = data;
// 如果已经没有节点了,结束递归
if (!(nodes && nodes.length)) {
return;
}
const newChildren = [];
for (const node of nodes) {
if (predicate(node, filterText)) {
// 如果自己(节点)符合条件,直接加入到新的节点集
newChildren.push(node);
// 并接着处理其 children,(因为父节点符合,子节点一定要在,所以这一步就不递归了)
node.children = this.arrayTreeFilter(node.children, predicate, filterText);
} else {
// 如果自己不符合条件,需要根据子集来判断它是否将其加入新节点集
// 根据递归调用 arrayTreeFilter() 的返回值来判断
const subs = this.arrayTreeFilter(node.children, predicate, filterText);
// 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中
// 1. 子孙节点中存在符合条件的,即 subs 数组中有值
// 2. 自己本身符合条件
if ((subs && subs.length) || predicate(node, filterText)) {
node.children = subs;
newChildren.push(node);
}
}
}
return newChildren;
}
filterFn = (data, filterText) => { //过滤函数
if (!filterText) {
return true;
}
return (
new RegExp(filterText, "i").test(data.title) //我是一title过滤 ,你可以根据自己需求改动
);
}
flatTreeFun = (treeData) => { //扁平化 tree
let arr = [];
const flatTree = (treeData) => {
treeData.map((item, index) => {
arr.push(item);
if (item.children && item.children.length > 0) {
flatTree(item.children);
item.children = [];
}
})
}
flatTree(treeData);
return arr;
}
expandedKeysFun = (treeData) => { //展开 key函数
if (treeData && treeData.length == 0) {
return [];
}
//console.log(treeData)
let arr = [];
const expandedKeysFn = (treeData) => {
treeData.map((item, index) => {
arr.push(item.key); //如果数据量小放这里可以
if (item.children && item.children.length > 0) {
//arr.push(item.key); //如果数据量大放这里可以
expandedKeysFn(item.children);
}
})
}
expandedKeysFn(treeData);
return arr;
}
onChange = (e) => { //搜索框 change事件
let value = e.target.value;
if (value == "") { //为空时要回到最初 的树节点
let { copyTree, copyExpandedKeys } = this.state;
// let res = this.arrayTreeFilter(JSON.parse(copyTree), this.filterFn, value);
// let expkey = this.expandedKeysFun(res);
this.setState({
treeData: JSON.parse(copyTree),
expandedKeys: copyExpandedKeys
})
} else {
let { copyTree, copyExpandedKeys } = this.state;
let res = this.arrayTreeFilter(JSON.parse(copyTree), this.filterFn, value);
let expkey = this.expandedKeysFun(res);
this.setState({
treeData: res,
expandedKeys: expkey,
searchValue:value
})
}
}
renderTreeNode = (data) => { //生成树结构函数
if (data.length == 0) {
return
}
let { expandedKeys, searchValue } = this.state;
return data.map((item) => {
const index = item.title.indexOf(searchValue);
const beforeStr = item.title.substr(0, index);
const afterStr = item.title.substr(index + searchValue.length);
const title =
index > -1 ? (
<span>
{beforeStr}
<span style={{ color: "red" }}>{searchValue}</span>
{afterStr}
</span>
) : (
<span>{item.title}</span>
);
if (item.children && item.children.length > 0) {
return <TreeNode key={item.key} title={title} >
{
this.renderTreeNode(item.children)
}
</TreeNode>
}
return <TreeNode key={item.key} title={title} ></TreeNode>
})
}
onExpand = expandedKeys => {
this.setState({
expandedKeys,
});
};
render() {
let { expandedKeys, treeData } = this.state;
return (
<div>
<Search style={{ marginBottom: 8 }} placeholder="Search" onChange={this.onChange} />
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={expandedKeys}
autoExpandParent={true}
// treeData={treeData}
>
{
this.renderTreeNode(treeData)
}
</Tree>
</div>
)
}
}
export default Index
antd Tree组件 搜索标红 例子 (可以在线演示)
二、这个是不标红
import React, { Component } from 'react';
import { Form, Input, Tree } from 'antd';
const { Search } = Input;
const treeData = [
{
title: '0-0',
key: '0-0',
children: [
{
title: '0-0-0',
key: '0-0-0',
children: [
{ title: '0-0-0-0-88', key: '0-0-0-0' },
{ title: '0-0-0-1', key: '0-0-0-1' },
{ title: '0-0-0-2', key: '0-0-0-2' },
],
},
{
title: '0-0-1',
key: '0-0-1',
children: [
{ title: '0-0-1-0', key: '0-0-1-0' },
{ title: '0-0-1-1', key: '0-0-1-1' },
{ title: '0-0-1-2', key: '0-0-1-2' },
],
},
{
title: '0-0-2',
key: '0-0-2',
},
],
},
{
title: '99',
key: '0-1',
children: [
{ title: '0-1-0-0', key: '0-1-0-0' },
{ title: '9988', key: '0-1-0-1' },
{ title: '0-1-0-2-99988', key: '0-1-0-2' },
],
},
{
title: '0-2',
key: '0-2',
},
];
class Index extends Component {
formRef = React.createRef();
constructor(props) {
super(props);
this.state = {
expandedKeys: [],//树节点展开key
treeData: [],
copyTree: [],//备份 treeData
copyExpandedKeys:[] //备份 展开key
}
}
componentDidMount() {
let a = this.expandedKeysFun(treeData); //展开key
let cp = JSON.stringify(treeData); //这个是最简单的 深拷贝
this.setState({
treeData: treeData,
expandedKeys: a,
copyTree: cp,
copyExpandedKeys:a
})
}
arrayTreeFilter = (data, predicate, filterText) => {
const nodes = data;
// 如果已经没有节点了,结束递归
if (!(nodes && nodes.length)) {
return;
}
const newChildren = [];
for (const node of nodes) {
if (predicate(node, filterText)) {
// 如果自己(节点)符合条件,直接加入到新的节点集
newChildren.push(node);
// 并接着处理其 children,(因为父节点符合,子节点一定要在,所以这一步就不递归了)
node.children = this.arrayTreeFilter(node.children, predicate, filterText);
} else {
// 如果自己不符合条件,需要根据子集来判断它是否将其加入新节点集
// 根据递归调用 arrayTreeFilter() 的返回值来判断
const subs = this.arrayTreeFilter(node.children, predicate, filterText);
// 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中
// 1. 子孙节点中存在符合条件的,即 subs 数组中有值
// 2. 自己本身符合条件
if ((subs && subs.length) || predicate(node, filterText)) {
node.children = subs;
newChildren.push(node);
}
}
}
return newChildren;
}
filterFn = (data, filterText) => { //过滤函数
if (!filterText) {
return true;
}
return (
new RegExp(filterText, "i").test(data.title) //我是一title过滤 ,你可以根据自己需求改动
);
}
flatTreeFun = (treeData) => { //扁平化 tree
let arr = [];
const flatTree = (treeData) => {
treeData.map((item, index) => {
arr.push(item);
if (item.children && item.children.length > 0) {
flatTree(item.children);
item.children = [];
}
})
}
flatTree(treeData);
return arr;
}
expandedKeysFun = (treeData) => { //展开 key函数
if (treeData && treeData.length == 0) {
return [];
}
//console.log(treeData)
let arr = [];
const expandedKeysFn = (treeData) => {
treeData.map((item, index) => {
arr.push(item.key);
if (item.children && item.children.length > 0) {
expandedKeysFn(item.children);
}
})
}
expandedKeysFn(treeData);
return arr;
}
onChange = (e) => { //搜索框 change事件
let value = e.target.value;
if (value == "") { //为空时要回到最初 的树节点
let { copyTree,copyExpandedKeys } = this.state;
// let res = this.arrayTreeFilter(JSON.parse(copyTree), this.filterFn, value);
// let expkey = this.expandedKeysFun(res);
this.setState({
treeData: JSON.parse(copyTree),
expandedKeys:copyExpandedKeys
})
} else {
let { copyTree, copyExpandedKeys } = this.state;
let res = this.arrayTreeFilter(JSON.parse(copyTree), this.filterFn, value);
let expkey = this.expandedKeysFun(res);
this.setState({
treeData: res,
expandedKeys: expkey
})
}
}
onExpand = expandedKeys => {
this.setState({
expandedKeys,
});
};
render() {
let { expandedKeys, treeData } = this.state;
return (
<div>
<Search style={{ marginBottom: 8 }} placeholder="Search" onChange={this.onChange} />
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={expandedKeys}
autoExpandParent={true}
treeData={treeData}
/>
</div>
)
}
}
export default Index
antd Tree组件 带 搜索 例子(可以在线演示)
数据量大造成的卡顿
可以给Tree加一个height属性:使用 height
属性则切换为虚拟滚动。
<Tree height={500}/>
这样可以缓解卡顿现象
总结:
也可以看看下面这两篇博客: