方法1: 循环12次, 性能较高
<script>
const data = [{
area_code: 43,
area_name: '湖南省'
},
{
area_code: 42,
area_name: '湖北省'
},
{
area_code: 23,
area_name: '河南省'
},
{
area_code: 4,
area_name: '北京市'
},
{
area_code: 4301,
area_name: '长沙市',
parent_code: 43
},
{
area_code: 430101,
area_name: '芙蓉区',
parent_code: 4301
},
{
area_code: 430102,
area_name: '天心区',
parent_code: 4301
},
{
area_code: 4302,
area_name: '湘潭市',
parent_code: 43
},
{
area_code: 4201,
area_name: '武冈',
parent_code: 42
},
{
area_code: 2301,
area_name: '开封市',
parent_code: 23
},
{
area_code: 401,
area_name: '朝阳区',
parent_code: 4
},
{
area_code: 402,
area_name: '海定区',
parent_code: 4
},
]
function transformTree(data, initCode) {
function tree(id) {
const arr = [];
data.
filter(item => item.parent_code === id).
forEach(element => {
arr.push({
label: element.area_name,
area_code: element.area_code,
children: tree(element.area_code)
})
});
return arr;
}
return tree(initCode);
}
const result = transformTree(data, undefined);
console.log(666, result);
</script>
方法2: 循环144次, 性能较低
function transformTree2(data, initCode) {
const cloneData = JSON.parse(JSON.stringify(data));
return cloneData.filter(father => {
const children = cloneData.filter(child => father.area_code === child.parent_code)
children.length > 0 ? father.children = children : null;
return father.parent_code === initCode;
})
}
React 渲染
class渲染
import React, { Component } from "react";
const treeData = {
title: "总览",
key: "big-title",
children: [
{
title: "0-0",
key: "0-0",
children: [
{
title: "0-0-0",
key: "0-0-0",
children: [
{ title: "0-0-0-0", 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: "0-1",
key: "0-1",
children: [
{ title: "0-1-0-0", key: "0-1-0-0" },
{ title: "0-1-0-1", key: "0-1-0-1" },
{ title: "0-1-0-2", key: "0-1-0-2" },
],
},
{
title: "0-2",
key: "0-2",
},
],
};
class Tree extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
get isFolder() {
return this.props.treeData.children && this.props.treeData.children.length;
}
toggle = () => {
this.setState({
isOpen: !this.state.isOpen
})
}
render() {
return (
<ul>
<li>
<div style={{cursor: 'pointer'}} onClick={this.toggle}>
{this.props.treeData.title}
<span>
{this.isFolder ? (this.state.isOpen ? " -" : " +") : null}
</span>
</div>
{this.isFolder ? (
<div style={{ display: this.state.isOpen ? "block" : "none" }}>
{this.props.treeData.children.map((item) => (
<TreeNode treeData={item} key={item.key} />
))}
</div>
) : null}
</li>
</ul>
);
}
}
class TreeTest extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Tree Demo</h1>
<TreeNode treeData={treeData} />
</div>
);
}
}
export default Tree;
Hooks渲染
const data = {
id: 0,
post: '指挥长',
name: '555',
children: [
{
name: '某某某',
mobile: 123456789,
},
],
postChildren: [{
id: 1,
name: '',
post: '副指挥长',
level: 2,
children: [
{
id: 2,
name: '某某某1',
post: '',
mobile: 123456781,
children: [],
},
{
id: 3,
name: '某某某2',
post: '',
mobile: 123456782,
children: [],
},
{
id: 4,
name: '某某某3',
post: '',
mobile: 123456783,
children: [],
},
],
postChildren: [
{
id: 5,
name: '',
post: '综合协调组',
level: 3,
children: [
{
id: 6,
name: '某某某4',
post: '喽啰',
mobile: 123456784,
children: [],
},
{
id: 7,
name: '某某某5',
post: '喽啰',
mobile: 123456785,
children: [],
},
{
id: 8,
name: '某某某6',
post: '喽啰',
mobile: 123456786,
children: [],
},
],
},
{
id: 9,
name: '',
level: 3,
post: '综合协调组',
children: [
{
id: 10,
name: '某某某7',
post: '喽啰',
mobile: 123456784,
children: [],
},
{
id: 11,
name: '某某某8',
post: '喽啰',
mobile: 123456785,
children: [],
},
{
id: 12,
name: '某某某9',
post: '喽啰',
mobile: 123456786,
children: [],
},
],
}],
}],
};
import React, { useState } from 'react';
function TreeNode({ treeData, treeData: { postChildren, children }, className, onClick }) {
const [open, setOpen] = useState(true);
const isFolder = () => postChildren && postChildren.length;
const toggle = () => {
setOpen(!open);
};
const handleLevel = (lx) => {
let level = 'level1';
if (lx === 2) {
level = 'level2';
}
if (lx === 3) {
level = 'level3';
}
return level;
};
return (
<div>
<div
className={`item${className ? ` ${className}` : ''}`}
onClick={(e) => {
onClick(treeData, e.target);
}}
>
<li>
<div style={{ cursor: 'pointer' }}>
<div className={`detail${open ? ' open' : ''}`}>
<i
className="iconfont iconsanjiaoxing"
onClick={(e) => {
e.stopPropagation();
toggle();
}}
/>
<span className="post">{treeData.post && treeData.post}</span>
<div>
<i className="iconfont iconwode mr-7" />
<span>{children && children.length}</span>
</div>
</div>
{
children && children.map(({ name, mobile }) => (
<div
className="second detail"
style={{ display: open ? 'flex' : 'none' }}
key={name}
>
<span className="name">{name}</span>
<div>
<span className="mobile">{mobile}</span>
<i className="iconfont iconzixunrexian theme-color" />
</div>
</div>
))
}
</div>
</li>
</div>
<ul>
{isFolder ? (
<div style={{ display: open ? 'block' : 'none' }}>
{postChildren && postChildren.map((item) => (
<div
key={item.id}
>
<TreeNode
treeData={item}
onClick={onClick}
className={handleLevel(item.level)}
/>
</div>
))}
</div>
) : null}
</ul>
</div>
);
}
function Tree({ onClick }) {
return (
<div style={{ marginRight: 10 }}>
<TreeNode
treeData={data}
onClick={onClick}
/>
</div>
);
}
export default Tree;
scss
.content {
display: flex;
align-items: flex-start;
max-height: 533px;
.header {
color: #fff;
margin-bottom: 10px;
}
.content-left {
max-height: 533px;
overflow-y: scroll;
30%;
margin-right: 15px;
color: #fff;
.item {
//display: none;
padding: 18px 8px 9px 32px;
background-color: rgba(0, 251, 255, .05);
margin-bottom: 2px;
position: relative;
cursor: pointer;
&:link {
box-shadow: 0 0 20px 8px rgba(134, 158, 123, 1) inset;
}
}
.level2 {
padding: 18px 8px 9px 37px;
.iconsanjiaoxing {
left: 13px;
}
}
.level3 {
padding: 18px 8px 9px 42px;
.iconsanjiaoxing {
left: 18px;
}
}
.item3 {
.iconsanjiaoxing {
left: 18px;
}
}
.second {
padding: 18px 0 17px;
border-bottom: 1px solid rgba(0, 251, 255, .1);
font-size: .875rem;
cursor: pointer;
&:last-child {
border-bottom: none;
}
}
.open {
.iconsanjiaoxing {
transform: rotate(-45deg);
}
}
.iconsanjiaoxing {
position: absolute;
left: 8px;
top: 23px;
margin-right: 18px;
font-size: .75rem;
color: #39FBF7;
transform: rotate(-90deg);
transition: transform .2s linear;
}
.mobile {
color: rgba(255, 255, 255, .6);
font-size: .75rem;
margin-right: 10px;
}
.name {
color: rgba(255, 255, 255, .8);
font-size: .875rem;
}
.active {
box-shadow: 0 0 20px 8px rgba(134, 158, 123, 1) inset;
}
.post {
font-weight: bold;
}
.detail {
display: flex;
align-items: center;
justify-content: space-between;
}
&::-webkit-scrollbar-track-piece {
background-color: transparent;
padding-left: 20px;
}
&::-webkit-scrollbar {
3px;
height: 3px;
margin-left: 20px;
}
&::-webkit-scrollbar-thumb {
background-color: #00FBFF;
background-clip: padding-box;
border-radius: 1px;
margin-left: 20px;
padding-left: 20px;
}
&::-webkit-scrollbar-thumb:hover {
background-color: #00FBFF;
}
}
.content-right {
max-height: 533px;
overflow-y: scroll;
70%;
color: #fff;
& > div {
border: 1px solid rgba(0, 251, 255, .2);
margin-right: 10px;
padding: 18px 25px;
}
&::-webkit-scrollbar-track-piece {
background-color: transparent;
}
&::-webkit-scrollbar {
3px;
height: 3px;
}
&::-webkit-scrollbar-thumb {
background-color: #00FBFF;
background-clip: padding-box;
border-radius: 1px;
}
&::-webkit-scrollbar-thumb:hover {
background-color: #00FBFF;
}
.title {
color: #39FBF7;
font-weight: bold;
font-size: 1.125rem;
}
.list {
li {
display: flex;
align-items: center;
justify-content: space-between;
padding: 22px 0;
border-bottom: 1px solid rgba(255, 255, 25, .1);
i {
font-size: 1.5rem;
color: #39FBF7;
cursor: pointer;
}
}
}
}
.content-center {
position: relative;
.header {
}
.list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
31%;
box-sizing: border-box;
padding: 18px 28px;
background-color: rgba(0, 251, 255, .05);
margin-bottom: 26px;
position: relative;
cursor: pointer;
color: #fff;
&:link {
box-shadow: 0 0 20px 8px rgba(134, 158, 123, 1) inset;
}
.item-header {
span:nth-child(1) {
color: #00FBFF;
font-weight: bold;
margin-right: 16px;
}
span:nth-child(2) {
color: rgba(255, 255, 255, .6);
font-size: .75rem;
}
}
.item-center {
display: inline-block;
margin: 8px 0 20px;
}
}
.active {
box-shadow: 0 0 20px 8px rgba(134, 158, 123, 1) inset;
}
}
.content-footer {
color: #fff;
.pagination-detail {
margin-right: 60px;
font-weight: bold;
span {
display: inline-block;
color: #00FBFF;
font-size: .875rem;
margin: 0 10px;
}
}
display: flex;
justify-content: flex-end;
}
}