处理树状结构/递归数据以及 React渲染
方法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; width: 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 { width: 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; width: 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 { width: 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 { width: 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; } }
标签:
JavaScript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现