虚拟滚动
当任务数量较多时(超过 100 个),虚拟滚动可以显著提升渲染性能。
工作原理
虚拟滚动只渲染当前可视区域内的任务,而不是渲染所有任务。这使得 GanttFlow 能够轻松处理数千条任务数据。
┌─────────────────────────────┐
│ Header (固定) │
├────────────┬────────────────┤
│ │ ████████████ │ ← 可视区域
│ Task List │ ████████████ │ 只渲染可见任务
│ │ ████████████ │
│ │ ████████████ │
├────────────┼────────────────┤
│ │ ████████████ │ ← 缓冲区
│ │ (虚拟空白) │ 保持滚动条正确
│ │ (虚拟空白) │
└────────────┴────────────────┘启用虚拟滚动
tsx
<EnhancedGanttChart
tasks={largeTaskList} // 假设有 1000+ 任务
virtualScrolling={true}
visibleTaskCount={50} // 可见任务数量
bufferSize={10} // 缓冲区大小
/>配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
virtualScrolling | boolean | false | 是否启用虚拟滚动 |
visibleTaskCount | number | 50 | 可见区域渲染的任务数 |
bufferSize | number | 10 | 上下缓冲区渲染的任务数 |
性能优化建议
合理设置可见数量
根据屏幕大小设置可见任务数:
tsx
// 小屏幕设备
<EnhancedGanttChart
virtualScrolling={true}
visibleTaskCount={30}
/>
// 大屏幕设备
<EnhancedGanttChart
virtualScrolling={true}
visibleTaskCount={80}
/>
// 响应式设置
function useVisibleTaskCount() {
const { height } = useWindowSize()
if (height < 600) return 25
if (height < 900) return 50
return 80
}配合自适应密度
可以结合自适应密度功能获得最佳体验:
tsx
<EnhancedGanttChart
virtualScrolling={true}
adaptiveDensity={true} // 自动调整布局密度
densityThreshold={100} // 超过此数量自动启用自适应
/>使用懒加载
对于超大数据集,可以配合懒加载:
tsx
const loadMoreTasks = async () => {
const newTasks = await fetchTasks(currentPage + 1)
setTasks([...tasks, ...newTasks])
}
<EnhancedGanttChart
tasks={tasks}
virtualScrolling={true}
onScrollBottom={loadMoreTasks}
/>性能对比
| 任务数量 | 无虚拟滚动 | 启用虚拟滚动 |
|---|---|---|
| 50 | ✅ 流畅 | ✅ 流畅 |
| 200 | ⚠️ 卡顿 | ✅ 流畅 |
| 500 | 🐢 明显卡顿 | ✅ 流畅 |
| 1000 | ❌ 无法使用 | ✅ 流畅 |
| 5000 | ❌ 崩溃 | ✅ 流畅 |
调试模式
开发时可以开启性能日志:
tsx
<EnhancedGanttChart
tasks={tasks}
virtualScrolling={true}
debugMode={true} // 显示性能日志
/>调试模式会显示:
- 当前渲染的任务数量
- 滚动位置
- FPS(帧率)
- 渲染时间
常见问题
Q: 启用虚拟滚动后,滚动不流畅?
A: 检查以下几点:
- 减少可见任务数:
tsx
<EnhancedGanttChart visibleTaskCount={30} />- 禁用动画:
tsx
<EnhancedGanttChart enableAnimations={false} />- 检查设备性能:虚拟滚动需要设备有足够的内存和处理能力
Q: 任务高度不一致时显示异常?
A: 确保所有任务有固定的行高,或设置 variableRowHeight={true}:
tsx
<EnhancedGanttChart
virtualScrolling={true}
rowHeight={44} // 固定行高
/>Q: 拖拽时虚拟滚动行为异常?
A: 拖拽过程中可以临时禁用虚拟滚动:
tsx
const [isDragging, setIsDragging] = useState(false)
<EnhancedGanttChart
tasks={tasks}
virtualScrolling={!isDragging}
onTaskDragStart={() => setIsDragging(true)}
onTaskDragEnd={() => setIsDragging(false)}
/>最佳实践
自动启用
tsx
// 当任务数量超过阈值时自动启用虚拟滚动
const shouldEnableVirtualScroll = tasks.length > 100
<EnhancedGanttChart
tasks={tasks}
virtualScrolling={shouldEnableVirtualScroll}
visibleTaskCount={shouldEnableVirtualScroll ? 50 : undefined}
/>任务数据优化
tsx
// ✅ 推荐:保持任务数据简洁
const tasks = largeTaskList.map(task => ({
id: task.id,
name: task.name,
start: task.start,
end: task.end,
progress: task.progress
}))
// ❌ 不推荐:保留大量无关数据
const tasks = largeTaskList // 可能包含 description, notes, assignees 等大量数据合理使用缓冲区
tsx
// 缓冲区太小会导致滚动时出现空白
<EnhancedGanttChart bufferSize={5} /> // 太小
// 缓冲区太大会影响性能
<EnhancedGanttChart bufferSize={50} /> // 太大
// 推荐:缓冲区为可见数量的 20%
<EnhancedGanttChart
visibleTaskCount={50}
bufferSize={10}
/>实现原理
虚拟滚动的核心原理:
1. 计算可视区域
- 根据滚动位置和容器高度
- 确定可见的任务索引范围
2. 计算渲染范围
- 可见范围 + 缓冲区
- 确定需要渲染的任务
3. 渲染任务
- 只渲染计算出的任务
- 使用 transform 定位
4. 保持滚动条正确
- 计算总高度(所有任务高度之和)
- 创建虚拟容器维持滚动条比例