基于Ant Design的Tree可搜索树形组件

Ant Design中的Tree不能直接拿来满足设计图的样子和需求,按还是基于andt的Tree进行了一些改造。

  • 问题:自定义树节点的展开/折叠图标
antd提供了一个switcherIcon属性,用来自定义图标

但是没有专门区分展开和折叠的图标样子,展开和折叠图标的区别,就是旋转角度而已。所以做不到设计图上的样子。

  • 方案:

icon={<><Icon type="plus-circle" /><Icon type="minus-circle" /></>}
我是通过在TreeNode节点上的icon属性上加入了2个图标,通过class去控制图标的显示。

生成的节点和搜索功能,都是通过函数的递归调用去完成。

直接上假数据和代码(提醒:下面是有涉及到 less 和 CSSModules 的用法)

[{
        "knowledgeId": 1,
        "knowledgeName": "数与式",
        "subjectId": 2,
        "phaseId": 2,
        "children": [{
            "knowledgeId": 2,
            "knowledgeName": "有理数",
            "subjectId": 2,
            "phaseId": 2,
            "children": [{
                "knowledgeId": 3,
                "knowledgeName": "正式和负数",
                "subjectId": 2,
                "phaseId": 2,
                "children": [{
                    "knowledgeId": 4,
                    "knowledgeName": "正式、负数的意义",
                    "subjectId": 2,
                    "phaseId": 2,
                }, {
                    "knowledgeId": 5,
                    "knowledgeName": "相反意义的量",
                    "subjectId": 2,
                    "phaseId": 2,
                }, {
                    "knowledgeId": 6,
                    "knowledgeName": "正负数在实际生活",
                    "subjectId": 2,
                    "phaseId": 2,
                }]
            }, {
                "knowledgeId": 7,
                "knowledgeName": "有理数的初步认识",
                "subjectId": 2,
                "phaseId": 2,
            }]
        }]
    }, {
        "knowledgeId": 8,
        "knowledgeName": "方程与不等式",
        "subjectId": 2,
        "phaseId": 2,
        "children": [{
            "knowledgeId": 9,
            "knowledgeName": "一元二次方程",
            "subjectId": 2,
            "phaseId": 2,
        }]
    }]
import React, { useState, useEffect } from 'react';
import style from './fineQuestion.less';
import { Icon, Select, Tree, Input } from "antd";
const { Search } = Input;
const { TreeNode } = Tree;

export default function QuestionMenu(props) {
    const [unfolds, setUnfolds] = useState([]);
    const [nowSelect, setNowSelect] = useState('');
    const [autoExpandParent, setAutoExpandParent] = useState(false);
    const [antistop, setAntistop] = useState(false);

//获取需要展开的节点
    function getKey(data, cun, value, expandedKeys) {
        data.map((item, i) => {
            cun = cun + ',' + item.knowledgeId;
            if (item.knowledgeName.indexOf(value) > -1) {
                expandedKeys.push(...cun.split(','))
            }
            if (item.hasOwnProperty('children')) {
                getKey(item.children, cun, value, expandedKeys);
            }
        })
    }
//输入框关键词搜索
    function onChange(e) {
        const { value } = e.target;
        const expandedKeys = [];
        if (value === '') {
            setAntistop(false)
            return
        }
        props.treeStructure.map(item => {
            let cun = item.knowledgeId;
            getKey(item.children, cun, value, expandedKeys);
        })

        setAntistop(value)
        setAutoExpandParent(true)
        setUnfolds([...new Set(expandedKeys)])
    };

//生成树节点
    function recursion(data) {
        return <>  {
            data.map((item, i) => (
                item.hasOwnProperty('children') ?
                    <TreeNode title={<span style={item.knowledgeName.includes(antistop) ? { color: 'rgb(255, 85, 0)' } : {}}>{item.knowledgeName}</span>} key={item.knowledgeId} icon={<><Icon type="plus-circle" /><Icon type="minus-circle" /></>} >
                        <> {recursion(item.children)}</>
                    </TreeNode> :
                    <TreeNode title={<span style={item.knowledgeName.includes(antistop) ? { color: 'rgb(255, 85, 0)' } : {
                        color: `${nowSelect == item.knowledgeId ? '#409EFF' : ''}`
                    }}>{item.knowledgeName}</span>} key={item.knowledgeId} />
            ))
        }
        </>
    }

    return (
      <div className={style.left}>
            <Search className={style.keyword} placeholder="输入知识点关键字" onChange={onChange} />
            <div style={{ position: 'relative', left: '-20px', width: 270, overflow: 'scroll', height: 'calc( 100% - 65px)' }}  >
                <Tree
                    switcherIcon={<></>}
                    showIcon={true}
                    expandedKeys={unfolds}
                    autoExpandParent={autoExpandParent}
                    onSelect={(selectedKeys, e) => {
                        let key = e.node.props.eventKey;
                        if (unfolds.length === 0) {
                            setUnfolds(selectedKeys)
                            return;
                        }
                        if (e.node.props.hasOwnProperty('children') && !unfolds.includes(key)) {
                            //展开
                            unfolds.push(key)
                        } else if (e.selectedNodes.length > 0 && !e.selectedNodes[0].props.children) {
                            // 最后一层
                            setNowSelect(key)
                        } else if (unfolds.includes(key)) {
                            // 收缩
                            let index = unfolds.indexOf(key)
                            unfolds.splice(index, 1)
                        }
                        setUnfolds(unfolds)
                        setAutoExpandParent(false)

                    }}>
                    {recursion(props.treeStructure)}
                </Tree>
            </div>
     </div>
    )
}

/*
treeStructure 树结构数据
*/
QuestionMenu.defaultProps = {
    treeStructure: []
};
.left {
    background   : rgba(255, 255, 255, 1);
    border-radius: 3px 3px 3px 3px;
    height       : 100%;
    flex         : 0 0 250px !important;
    max-width    : 250px !important;
    overflow     : hidden;
    .keyword {
        margin : 20px 0 10px;
        padding: 0 13px;
        height : 36px;
        input {
            border-radius: 18px;
            padding-left : 16px;
        }
        span {
            font-size: 20px;
            right    : 30px;
        }
    }
    :global(.ant-tree-node-content-wrapper-close) {
        :global(.anticon-minus-circle) {
            display: none;
        }
    }
    :global(.ant-tree-node-content-wrapper-open) {
        :global(.anticon-plus-circle) {
            display: none;
        }
    }
    :global(.ant-tree) {
        li {
            :global(.ant-tree-node-content-wrapper.ant-tree-node-selected) {
                background: #fff !important;
                color     : #000000 !important;
            }
            :global(.ant-tree-node-content-wrapper) {
                color: #000000;
                &:hover {
                    background: #fff !important;
                    color     : #409EFF !important;
                }
            }
        }
    }
}

因为数据量大,可能会接口比较慢,或者这边生成时间比较长,加一个Spin组件,用户体验会好点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容