一个高性能的 React TreeView 组件,支持虚拟列表、展开/收起、节点选择等功能。
npm install @zcllc/treeviewbash
npm install @zcllc/treeview
或
yarn add @zcllc/treeview
`
🚀 快速开始
`tsx
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 (
data={data}
containerStyle={{ height: 400 }}
/>
);
}
`
📋 类型定义
$3
树节点的基础数据结构:
`typescript
export type TreeNode = {
// 必填
keyName: string;
// 可选 - 显示和样式
displayName?: string; // 节点显示名称(默认使用 keyName)
extraContent?: string; // 追加的显示内容
iconClass?: string; // 自定义图标 CSS 类
// 可选 - 状态
isExpanded?: boolean; // 节点展开状态
checked?: boolean; // 节点选中状态
// 可选 - 数据
children?: TreeNode[]; // 子节点
data?: { [key: string]: unknown }; // 自定义携带数据
}
`
$3
运行时内部使用的扩展类型(包含内部属性):
`typescript
export type TreeNodeInset = TreeNode & {
// 内部属性
key?: string; // 内部唯一 key(自动生成)
parentKey?: string; // 父节点 key
leafLevel?: number; // 节点深度
hasChildren?: boolean; // 是否存在子节点
positionTop?: number; // 节点在容器中的位置
visible?: boolean; // 节点的可见状态
}
`
$3
TreeView 组件的 Props:
`typescript
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; // 节点展开/折叠
}
`
💡 功能特性
$3
✅ 高性能:只渲染可见节点,支持数万级别数据
- 自动计算可见区域
- 按需渲染,快速滚动响应
- 内存占用低
$3
✅ 双击展开:双击节点可展开/收起(如果有子节点)
✅ 递归展开:展开父节点时自动隐藏所有子节点的子节点
✅ 状态保持:数据更新后保留节点的展开状态
$3
✅ 复选框:设置 allowCheck=true 启用
✅ 联动选择:
- 选中父节点时,所有子节点被选中
- 选中所有子节点时,父节点自动被选中
- 选中部分子节点时,父节点为选中状态
$3
✅ iconfont 支持:通过 iconClass 自定义节点图标
✅ HTML 内容:displayName 支持 HTML 内容
$3
✅ 右键菜单:onContextMenu 事件
✅ 拖拽:onDrag 事件
✅ 节点选择:点击节点高亮
📖 使用示例
$3
`tsx
import TreeView, { type TreeNode} from '@zcllc/treeview';
const data: TreeNode[] = [
{
keyName: 'folder1',
displayName: '📁 文件夹 1',
children: [
{
keyName: 'file1',
displayName: '📄 文件 1.txt'
}
]
}
];
`
$3
`tsx
data={data}
allowCheck={true}
onCheckedChange={(checkedNodes) => {
console.log('选中的节点:', checkedNodes);
}}
/>
`
$3
`tsx
const data: TreeNode[] = [
{
keyName: 'node1',
displayName: '节点 1',
extraContent: '(未读)',
children: [...]
}
];
data={data}
showExtraContent={true}
/>
`
$3
`tsx
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);
}}
/>
`
$3
`tsx
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)
📝 更新日志
$3
-- 支持动态计算节点尺寸
-- 当从外部样式改变节点尺寸时, 不会影响虚拟滚动的计算
$3
-- 修改类型导出TreeNode, TreeNodeInset
-- TreeNode为组件标准节点数据.
-- TreeNodeInset为组件内部使用的数据格式.
$3
- ✅ 修复类型定义中的循环引用问题
- ✅ 导出完整的 TreeNode 和 TreeViewProps 类型
- ✅ 增强 TypeScript 类型支持
📄 许可证
ISC
---
常见问题
$3
A: 使用 onCheckedChange 回调获取所有选中的节点数组。
$3
A: 在 onNodeExpand 中检测节点展开时,动态更新数据源,组件会自动重新渲染。
$3
A: 目前节点高度固定为 24px,如需修改需要调整源码中的 nodeHeight 值。
$3
A: 通过 iconClass 属性传入 CSS 类名,确保 CSS 文件已加载(如 iconfont)。
$3
A: 支持,组件会渲染 displayName` 中的 HTML 内容,但需在组件中安全处理。