feat(ux): U1 虚拟滚动 — Pod/事件/审计/命令列表大数据量渲染优化
- 安装 @tanstack/react-virtual@3.14.4 - 新增 hooks/useVirtualRows.ts 可复用虚拟滚动 Hook - PodsTab: 全量渲染→虚拟滚动, 支持 1000+ Pod + 动态行高(展开行) - EventTable: 移除 maxRows=200 截断, 万级事件流畅渲染 - AuditOperationsTab: shadcn Table→虚拟滚动 CSS Grid 布局 - SessionCommandsPanel: 虚拟滚动, page_size 200→500 - npm run build ✅, tsc --noEmit ✅, 17/17 集成测试通过
This commit is contained in:
1 parent
e4f1018ca1
commit
f2069fe3f0
11 files changed
+673
-330
No files matched your search
@@ -0,0 +1,74 @@
|
||||
// useVirtualRows — 虚拟滚动 Hook,基于 @tanstack/react-virtual
|
||||
// 用于大列表(1000+ 行)场景的性能优化,只渲染可见区域的行
|
||||
// 用法:
|
||||
// const { scrollRef, virtualRows, totalHeight } = useVirtualRows({
|
||||
// count: data.length, estimateSize: () => 40, overscan: 10,
|
||||
// });
|
||||
import { useRef, useCallback } from 'react';
|
||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||
|
||||
export interface VirtualRowsOptions {
|
||||
count: number;
|
||||
estimateSize: (index: number) => number;
|
||||
overscan?: number;
|
||||
/** 滚动容器的 padding 顶部像素(影响虚拟化偏移计算) */
|
||||
paddingTop?: number;
|
||||
}
|
||||
|
||||
export interface VirtualRowsResult {
|
||||
/** 绑定到滚动容器 div 的 ref */
|
||||
scrollRef: React.RefObject<HTMLDivElement>;
|
||||
/** 当前可见+overscan 范围内的虚拟行 */
|
||||
virtualRows: ReturnType<ReturnType<typeof useVirtualizer>['getVirtualItems']>;
|
||||
/** 虚拟容器的总高度(用于设置 spacer 高度) */
|
||||
totalHeight: number;
|
||||
/** 滚动到指定 index */
|
||||
scrollToIndex: (index: number) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚拟滚动 Hook
|
||||
*
|
||||
* ```tsx
|
||||
* const { scrollRef, virtualRows, totalHeight } = useVirtualRows({
|
||||
* count: items.length, estimateSize: () => 40, overscan: 8,
|
||||
* });
|
||||
* return (
|
||||
* <div ref={scrollRef} style={{ height: 500, overflow: 'auto' }}>
|
||||
* <div style={{ height: totalHeight, position: 'relative' }}>
|
||||
* {virtualRows.map(vr => (
|
||||
* <div key={vr.key} style={{ position: 'absolute', top: vr.start, height: vr.size, width: '100%' }}>
|
||||
* {renderRow(items[vr.index])}
|
||||
* </div>
|
||||
* ))}
|
||||
* </div>
|
||||
* </div>
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export function useVirtualRows({
|
||||
count,
|
||||
estimateSize,
|
||||
overscan = 8,
|
||||
}: VirtualRowsOptions): VirtualRowsResult {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const virtualizer = useVirtualizer({
|
||||
count,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
estimateSize,
|
||||
overscan,
|
||||
});
|
||||
|
||||
const virtualRows = virtualizer.getVirtualItems();
|
||||
const totalHeight = virtualizer.getTotalSize();
|
||||
|
||||
const scrollToIndex = useCallback(
|
||||
(index: number) => {
|
||||
virtualizer.scrollToIndex(index, { align: 'start' });
|
||||
},
|
||||
[virtualizer],
|
||||
);
|
||||
|
||||
return { scrollRef, virtualRows, totalHeight, scrollToIndex };
|
||||
}
|
||||
Reference in new issue
Block a user