@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-node(padding-left)移至.tree-node-name(padding-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 内容,但需在组件中安全处理。
