npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zcllc/treeview

v2.0.10

Published

一个高性能的 React TreeView 组件,支持虚拟列表、展开/收起、节点选择等功能。

Downloads

216

Readme

TreeView 组件库

一个高性能的 React TreeView 组件,支持虚拟列表、展开/收起、节点选择等功能。

📦 安装

npm install @zcllc/treeview
# 或
yarn add @zcllc/treeview

🚀 快速开始

import TreeView, { type TreeViewProps, type TreeNode } from '@zcllc/treeview';

const data: TreeNode[] = [
  {
    keyName: 'node1',
    displayName: '节点 1',
    children: [
      {
        keyName: 'node1-1',
        displayName: '节点 1-1'
      }
    ]
  },
  {
    keyName: 'node2',
    displayName: '节点 2'
  }
];

function App() {
  return (
    <TreeView 
      data={data}
      containerStyle={{ height: 400 }}
    />
  );
}

📋 类型定义

TreeNode / TreeNodeInset

树节点的基础数据结构:

export type TreeNode = {
  // 必填
  keyName: string;
  
  // 可选 - 显示和样式
  displayName?: string;              // 节点显示名称(默认使用 keyName)
  extraContent?: string;             // 追加的显示内容
  iconClass?: string;                // 自定义图标 CSS 类
  
  // 可选 - 状态
  isExpanded?: boolean;              // 节点展开状态
  checked?: boolean;                 // 节点选中状态
  
  // 可选 - 数据
  children?: TreeNode[];         // 子节点
  data?: { [key: string]: unknown }; // 自定义携带数据
}

TreeNodeInset

运行时内部使用的扩展类型(包含内部属性):

export type TreeNodeInset = TreeNode & {
  // 内部属性
  key?: string;          // 内部唯一 key(自动生成)
  parentKey?: string;    // 父节点 key
  leafLevel?: number;    // 节点深度
  hasChildren?: boolean; // 是否存在子节点
  positionTop?: number;  // 节点在容器中的位置
  visible?: boolean;     // 节点的可见状态
}

TreeViewProps

TreeView 组件的 Props:

export interface IProps {
  // 数据
  data: TreeNode[];
  
  // 样式
  className?: string;
  containerStyle?: React.CSSProperties;
  
  // 功能开关
  allowCheck?: boolean;        // 是否显示复选框
  showScrollBarX?: boolean;    // 是否显示横向滚动条
  showExtraContent?: boolean;  // 是否显示 extraContent
  
  // 事件回调
  onCheckedChange?: (checkedNodes: TreeNode[]) => void;      // 选中状态变化
  onContextMenu?: (e: React.MouseEvent, nodeData: TreeNode) => void; // 右键菜单
  onDoubleClick?: (nodeData: TreeNode) => void;              // 双击节点
  onDrag?: (e: React.DragEvent, nodeData: TreeNode) => void; // 拖拽节点
  onRender?: (insetData: TreeNode[]) => void;                // 渲染完成
  onNodeExpand?: (nodeData: TreeNode) => void;               // 节点展开/折叠
}

💡 功能特性

1. 虚拟列表渲染(Virtual Scrolling)

高性能:只渲染可见节点,支持数万级别数据

  • 自动计算可见区域
  • 按需渲染,快速滚动响应
  • 内存占用低

2. 节点展开/收起

双击展开:双击节点可展开/收起(如果有子节点) ✅ 递归展开:展开父节点时自动隐藏所有子节点的子节点 ✅ 状态保持:数据更新后保留节点的展开状态

3. 多选支持

复选框:设置 allowCheck=true 启用 ✅ 联动选择

  • 选中父节点时,所有子节点被选中
  • 选中所有子节点时,父节点自动被选中
  • 选中部分子节点时,父节点为选中状态

4. 自定义图标

iconfont 支持:通过 iconClass 自定义节点图标 ✅ HTML 内容displayName 支持 HTML 内容

5. 交互事件

右键菜单onContextMenu 事件 ✅ 拖拽onDrag 事件 ✅ 节点选择:点击节点高亮

📖 使用示例

基础示例

import TreeView, { type TreeNode} from '@zcllc/treeview';

const data: TreeNode[] = [
  {
    keyName: 'folder1',
    displayName: '📁 文件夹 1',
    children: [
      {
        keyName: 'file1',
        displayName: '📄 文件 1.txt'
      }
    ]
  }
];

<TreeView data={data} containerStyle={{ height: 600 }} />

启用复选框

<TreeView 
  data={data}
  allowCheck={true}
  onCheckedChange={(checkedNodes) => {
    console.log('选中的节点:', checkedNodes);
  }}
/>

显示额外内容

const data: TreeNode[] = [
  {
    keyName: 'node1',
    displayName: '节点 1',
    extraContent: '<span style="color: red;">(未读)</span>',
    children: [...]
  }
];

<TreeView 
  data={data}
  showExtraContent={true}
/>

处理节点事件

<TreeView
  data={data}
  onDoubleClick={(node) => {
    console.log('双击节点:', node.keyName);
  }}
  onNodeExpand={(node) => {
    console.log('展开/收起:', node.keyName, '展开状态:', node.isExpanded);
  }}
  onContextMenu={(e, node) => {
    console.log('右键点击:', node.keyName);
    // 显示自定义菜单
  }}
  onDrag={(e, node) => {
    console.log('拖拽节点:', node.keyName);
  }}
/>

自定义样式

<TreeView
  data={data}
  className="my-custom-tree"
  containerStyle={{
    height: 500,
    border: '1px solid #ccc',
    borderRadius: 4
  }}
/>

🎨 样式定制

组件使用 SCSS 编写,支持通过 CSS 覆盖样式。主要 CSS 类:

  • .tree-view-container - 容器
  • .tree-view-scroller - 滚动容器
  • .tree-node - 节点
  • .tree-node-name - 节点名称区域
  • .tree-node-name.active - 活跃节点
  • .tree-open / .tree-close - 展开/收起箭头状态
  • .pd-* - 节点缩进(如 .pd-5, .pd-15 等)

📐 性能指标

  • 节点高度: 24px (固定)
  • 虚拟窗口: 容器高度 + 10 个额外节点高度的缓冲
  • 滚动节流: 基于 ResizeObserver 和滚动事件优化

⚙️ 配置项

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | data | TreeNode[] | - | 树形数据(必填) | | className | string | - | 自定义 CSS 类名 | | containerStyle | React.CSSProperties | - | 容器样式(建议设置 height) | | allowCheck | boolean | false | 启用复选框 | | showScrollBarX | boolean | false | 显示横向滚动条 | | showExtraContent | boolean | false | 显示额外内容 | | onCheckedChange | function | - | 选中状态变化回调 | | onContextMenu | function | - | 右键菜单回调 | | onDoubleClick | function | - | 双击回调 | | onDrag | function | - | 拖拽回调 | | onRender | function | - | 渲染完成回调 | | onNodeExpand | function | - | 节点展开/收起回调 |

🔗 相关依赖

  • React >= 18.0.0
  • React-DOM >= 18.0.0
  • uuid (用于生成节点 key)

📝 更新日志

v2.0.10

  • 修复当传入data变为空数组时, 已渲染的旧节点没有消失的问题.

v2.0.9

  • 修复外部 CSS 修改节点高度后,首次加载时节点定位仍按默认高度(24px)计算的问题
  • 使用 useLayoutEffect 替代 setTimeout 进行节点高度探测,在浏览器绘制前同步修正,消除位置闪烁
  • 调整缩进方案:将缩进从 .tree-nodepadding-left)移至 .tree-node-namepadding-left),整行(含缩进区域)均可正确应用背景色
  • .tree-node 新增 active 类,方便外部 CSS 对选中行整体设置样式

v2.0.8

-- 支持动态计算节点尺寸 -- 当从外部样式改变节点尺寸时, 不会影响虚拟滚动的计算

v2.0.7

-- 修改类型导出TreeNode, TreeNodeInset -- TreeNode为组件标准节点数据. -- TreeNodeInset为组件内部使用的数据格式.

v2.0.3

  • ✅ 修复类型定义中的循环引用问题
  • ✅ 导出完整的 TreeNode 和 TreeViewProps 类型
  • ✅ 增强 TypeScript 类型支持

📄 许可证

ISC


常见问题

Q: 如何获取选中的节点?

A: 使用 onCheckedChange 回调获取所有选中的节点数组。

Q: 如何支持异步加载子节点?

A: 在 onNodeExpand 中检测节点展开时,动态更新数据源,组件会自动重新渲染。

Q: 节点高度可以修改吗?

A: 目前节点高度固定为 24px,如需修改需要调整源码中的 nodeHeight 值。

Q: 如何使用自定义图标?

A: 通过 iconClass 属性传入 CSS 类名,确保 CSS 文件已加载(如 iconfont)。

Q: displayName 支持 HTML 吗?

A: 支持,组件会渲染 displayName 中的 HTML 内容,但需在组件中安全处理。