前端实现一个Tree组件,您看这篇就够了

个人的使用React开发的组件库x-react-design已开源

npm地址:https://www.npmjs.com/package/x-react-design?activeTab=readme

仓库地址:https://gitee.com/xian-jin/x-design

Tree组件,也就是树组件,数据结构当中的树也与此类似。开发树组件的难点是什么:是如何构建子树,其实很容易想到用递归构建子树。

这里Tree组件分了两种:节点名称前面带复选框的和不带复选框的。
1、不带复选框:
在这里插入图片描述
2、带复选框的:
在这里插入图片描述
树组件代码:

import { useState, useMemo, Fragment } from 'react'
import DownTriangle from '../Icons/DownTriangleIcon'
import RightTriangle from '../Icons/RightTriangleIcon'
import './index.css'

const Tree = (props) => {
    const [treeData, setTreeData] = useState(props.treeData || [])

    const handleInitTreeData = (data, field, type, node) => {
        let arr = []
        function loop(data) {
            return data.map(item => {
                if(type === 'init') {
                    item[field] = false
                } else if(type === 'update' && node.val === item.val) {
                    item[field] = !item[field]
                }
                if(item.children && Array.isArray(item.children)) {
                    item.children = loop(item.children)
                }
                return item
            })
        }
        arr = loop([...data])
        return arr
    }

    const tempData = useMemo(() => {
        return handleInitTreeData([...props.treeData], 'isSelected', 'init')
    }, [props.treeData])

    

    const clickTreeNode = (node) => {
        let arr = []
        arr = handleInitTreeData([...treeData], 'isSelected', 'update', node)
        setTreeData(arr)
        props.onChange && props.onChange(node.val, node.label, node.isSelected)
    }

    const renderTree = (treeDataArr) => {
        let arr = []
        function loop(data, level) {
            return data.map(item => {
                let newLevel = level + 1
                return <Fragment key={JSON.stringify(item)}>
                    <span 
                    className="tree-node-label"
                    onClick={() => {clickTreeNode(item)}}
                    >
                        {
                            (item.children && item.children.length > 0) ?
                            (item.isSelected ? <DownTriangle /> : <RightTriangle />)
                            :
                            <span className='tree-node-label-left-empty'></span>
                        }
                        {
                            props.showCheckbox ?
                            <input
                            type="checkbox"
                            checked={item.isSelected}
                            />
                            : null
                        }
                        <span>
                            {
                                item.label
                            }
                        </span>
                    </span>
                    {
                        item.isSelected ?
                        <div 
                        className="tree-node-item"
                        style={{paddingLeft: 15 * newLevel}}
                        >
                            {
                                item.children ? 
                                loop(item.children, newLevel)
                                : null
                            }
                        </div>
                        : null
                    }
                </Fragment>
            })
        }
        arr = loop([...treeDataArr], 0)
        return arr
    }

    return <div 
        className="tree-container"
        >
        {
            renderTree(tempData)
        }
    </div>
}

export default Tree

样式文件index.css:

.tree-container {}

.tree-node-label {
    display: flex;
    cursor: pointer;
}

.tree-node-label:hover {
    color: #00d5ff;
}

.tree-node-label-left-empty {
    display: inline-block;
    width: 16px;
    height: 16px;
}

使用Tree组件的代码:

import Tree from '../../components/Tree'

const data = [
    {
        label: '节点1',
        val: 'node-1',
    },
    {
        label: '节点2',
        val: 'node-2',
        children: [
            {
                label: '节点2-1',
                val: 'node-2-1',
            },
            {
                label: '节点2-2',
                val: 'node-2-2',
            },
        ]
    },
    {
        label: '节点3',
        val: 'node-3',
        children: [
            {
                label: '节点3-1',
                val: 'node-3-1',
                children: [
                    {
                        label: '节点3-1-1',
                        val: 'node-3-1-1',
                    },
                    {
                        label: '节点3-1-2',
                        val: 'node-3-1-2',
                    },
                ]
            },
        ]
    },
]

const MyTree = () => {

    const handleChange = (val, label, isSelected) => {
        console.log(val, label, isSelected);
    }

    return <div>
        <Tree treeData={data} showCheckbox={true} onChange={handleChange} />
    </div>
}

export default MyTree

有些参数解释一下:treeData代表的就是节点树数据,showCheckbox代表节点名称前面是否显示复选框,onChange代表的是点击节点的事件。其他参数和功能后续完善。

在Tree组件里renderTree函数是重点,renderTree是构建树结构的函数,使用了递归,level参数是标明树在第几层,利用newLevel设置每个节点距离左边的padding距离,以构建出树状。

目前写的功能能够满足基本功能,后续在完善其它功能。、

未完,待续。。。

**附言 :**x-react-design组件库组件:
在这里插入图片描述

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值