开发react树形组件的初衷是使其自定义更方便与自己的业务更切合,使其样式、功能交互更多元化,随业务随意修改。
如果对你用帮助,点赞加关注,小编会更新更多精彩内容
直接上代码:
js代
import styles from './index.less'
import React, { Component } from 'react';
class TreeComponent extends Component {
constructor(props) {
super(props);
this.state = {
expandedNodes: [], // 用于存储展开的节点
};
}
toggleNode = (nodeId) => {
const { expandedNodes } = this.state;
const isExpanded = expandedNodes.includes(nodeId);
if (isExpanded) {
this.setState({
expandedNodes: expandedNodes.filter((key) => key !== nodeId),
});
} else {
this.setState({
expandedNodes: [...expandedNodes, nodeId],
});
}
};
renderTree = (nodes, level = 0) => {
return nodes.map((node) => {
// 每一节点收缩
const isExpanded = this.state.expandedNodes.includes(node.key);
// 每一级是否有子节点
const hasChildren = node.children && node.children.length > 0;
// 是否是最后一级
const isLastLevel = node.children?false:true
// 节点数
const number = node.children && node.children.length
return (
<div key={node.id}>
<div style={{ paddingLeft: level * 115 }}>
{<div className={styles['queryTree-TreeNode-name']}>
<div className={`${styles['queryTree-TreeNode-name-text']}
${level===0?styles['one-text']:isLastLevel?styles['end-text']:''}`} >
{/* 连线 竖线*/}
{
new Array(level).fill(level).map((item,index)=>
<span key={index} style={{left:`${-115*(index) + 24}px`}} className={styles['queryTree-TreeNode-name-line-p']}>
<span className={styles['queryTree-TreeNode-name-line-expanded']}></span>
</span>
)
}
{/* 连线 横线子节点线*/}
{level!==0&&
<span className={styles['queryTree-TreeNode-name-line-f']}>
<span className={styles['queryTree-TreeNode-name-line']}></span>
</span>
}
{/*名字 和节点数 */}
<div className={styles['text-width']} >
<span className={styles['text-width-span']}>
{node.title} {number?'('+number+')':''}
</span>
{/* 收缩 按钮 */}
{hasChildren&&(
<div onClick={() => this.toggleNode(node.key)} className={styles['treeNode-shrink']}>
{isExpanded ? '-' : '+'}
</div>
)}
{isLastLevel && (
<a >
详情
</a>
)}
</div>
</div>
</div> }
</div>
{/* 展开时加载子节点 */}
{isExpanded && hasChildren && (
<div style={{ }}>
{this.renderTree(node.children, level + 1)}
</div>
)}
</div>
);
});
};
render() {
// const { data } = this.props;
const data = [
{
title: 'parent 1',
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
children: [
{
title: 'leaf',
key: '0-0-0-0',
},
{
title: 'leaf',
key: '0-0-0-1',
},
{
title: 'leaf',
key: '0-0-0-2',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [
{
title: 'leaf',
key: '0-0-1-0',
},
],
},
{
title: 'parent 1-2',
key: '0-0-2',
children: [
{
title: 'leaf',
key: '0-0-2-0',
},
{
title: 'leaf',
key: '0-0-2-1',
},
],
},
],
},
];
// const loadStartTime = performance.now(); //
return <div className={styles['queryTree-TreeNode']}>
{
this.renderTree(data)
}
{/* {
performance.now() - loadStartTime
} */}
</div>;
}
}
export default TreeComponent;
index.less代码
:
queryTree-TreeNode{
position: relative;
height: 500px;
width: 1338px;
overflow: auto;
&-name{
display: flex;
justify-items: center;
align-items: center;
&-text{
display: flex;
justify-content:space-between ;
justify-items: center;
align-items: center;
.text-width{
width: 230px;
display: flex;
justify-content:space-between ;
justify-items: center;
background: rgba(11,78,149,0.5);
border: 1px solid #227EF0;
border-radius: 5px;
margin-top: 5px;
&-span{
padding: 5px;
width: 190px;
display: block;
}
}
}
.end-text{
.text-width{
border: none;
border-left:1px solid #1B8AFF ;
.text-width-span{
border: none;
border-radius: 5px;
border-left:3px solid #1B8AFF ;
}
}
}
.treeNode-shrink{
display: flex;
justify-content:center ;
align-items: center;
align-self: center;
width: 20px;
height: 20px;
line-height: 20px;
background: rgba(27,138,255,0.5);
border-radius: 50%;
cursor: pointer;
margin-right: 3px;
}
&-line-f,&-line-p{
position: relative;
flex: none;
align-self: stretch;
width: 24px;
margin: 0;
line-height: 24px;
text-align: center;
user-select: none;
}
&-line,&-line-expanded{
position: relative;
z-index: 1;
display: inline-block;
width: 100%;
height: 100%;
}
&-line:before,&-line-expanded::before{
position: absolute;
top: 0;
inset-inline-end: 12px;
bottom: -4px;
margin-inline-start: -1px;
border-inline-end: 1px solid #8AC5ED;
content: "";
}
&-line:after{
position: absolute;
width: 10px;
height: 50%;
border-bottom: 1px solid #8AC5ED;
content: "";
}
&-line-p{
width: 0px;
}
&-line-expanded{
}
&-line-expanded::before{
}
.one-text{
// width: 40px;
// height: 100%;
// background: rgba(11,78,149,0.5);
// border: 1px solid #227EF0;
// border-radius: 5px;
}
a{
text-decoration:underline;
color: #00A6FF;
display: block;
width:32px;
padding-top: 5px;
}
}
}