如何在React中实现类似IDE默认文件结构的树形组件渲染
如何在React中实现类似IDE默认文件结构的树形组件渲染
我太懂你卡了两天的感受了,树形结构的递归渲染刚开始确实容易摸不着头绪,咱们一步步把这个文件树给搞出来!
第一步:改造TreeNode组件,让它支持递归渲染和交互
你的TreeNode现在只能渲染单个节点,得让它能识别子节点、处理展开收起,还要区分文件夹和文件的图标,另外还要根据层级做缩进。咱们修改一下:
import React, { useState } from "react"; import classes from "./TreeNode.module.css"; function TreeNode({ node, level }) { // 用mock里的opened字段作为初始展开状态 const [isOpened, setIsOpened] = useState(node.opened); // 切换展开/收起状态 const toggleOpen = () => { setIsOpened(!isOpened); }; // 根据节点类型返回对应图标 const getNodeIcon = () => { // 注意你mock里的类型是`FOALDER`,应该是`FOLDER`的笔误,实际代码记得修正! if (node.type === "FOALDER") { return ( <svg xmlns="http://www.w3.org/2000/svg" fill="#3B4045" width="20" height="20" viewBox="0 0 20 20"> <path d="M20,6h-8l-2-2H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z"></path> </svg> ); } else { // 文件类型的图标,你可以换成自己喜欢的样式 return ( <svg xmlns="http://www.w3.org/2000/svg" fill="#3B4045" width="20" height="20" viewBox="0 0 20 20"> <path d="M14,2H6C4.9,2,4,2.9,4,4v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V8L14,2z M16,18H6V4h7v4h3V18z"></path> </svg> ); } }; return ( <div> <div className={classes.treeNode} style={{ paddingLeft: `${level * 20}px` }} // 根据层级设置缩进,20px可自定义 onClick={node.type === "FOALDER" ? toggleOpen : undefined} > <div className={classes.treeNodeType}> {/* 只有文件夹显示展开/收起箭头 */} {node.type === "FOALDER" && ( <span style={{ marginRight: 6, display: "inline-block" }}> {isOpened ? "▼" : "▶"} </span> )} {getNodeIcon()} </div> <div className={classes.treeNodeTitle}> {node.title} </div> </div> {/* 文件夹展开时才渲染子节点 */} {isOpened && node.type === "FOALDER" && node.children.length > 0 && ( <div> {node.children.map(child => ( <TreeNode key={child.id} node={child} level={level + 1} /> ))} </div> )} </div> ); } export default TreeNode;
第二步:修改Main组件,渲染完整文件树
现在只需要把根节点逐个传给TreeNode,递归逻辑会自动处理所有子节点:
import files from "../../mock/files"; import "../../styles/Main.css"; import TreeNode from "../treenode/TreeNode"; function Main() { return ( <div className="wrapper"> <div className="tree"> {files.map((rootNode) => ( <TreeNode key={rootNode.id} node={rootNode} level={0} /> ))} </div> </div> ); } export default Main;
可选:优化交互样式
可以在TreeNode.module.css里加一点交互反馈,让体验更贴近IDE:
.treeNode { display: flex; align-items: center; padding: 3px 6px; cursor: pointer; gap: 8px; } .treeNode:hover { background-color: #f1f3f4; border-radius: 4px; } .treeNodeTitle { user-select: none; }
小提醒
你mock数据里的FOALDER是拼写错误,实际开发记得改成FOLDER,不然类型判断会失效哦!
备注:内容来源于stack exchange,提问作者Matvey Androsyuk
相关产品推荐
相关产品推荐

