antd Tree 组件 带搜索

前言:

antd Tree组件带搜索,官网示例感觉很麻烦,不容易让人懂,我就自己实现了一个。

antd 3.xTree带搜索(官网示例)

antd 4.x 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}/>

这样可以缓解卡顿现象

antd tree虚拟滚动

总结:

 也可以看看下面这两篇博客:

antd-tree组件带搜索框的使用及踩坑(只保留搜索的内容并且标红)

antd-tree组件带搜索框的使用及踩坑(只标红)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

崽崽的谷雨

漫漫前端路,摸爬滚打

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值