You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:13:06