Virtualizer
用于高效渲染大列表和大网格的虚拟滚动组件
Virtualizer 基于 @tanstack/react-virtual 封装,提供 VirtualList 和 VirtualGrid 两个常用组件,并 re-export useVirtualizer、useWindowVirtualizer 供更底层的自定义场景使用。
import { VirtualList, VirtualGrid, useVirtualizer, useWindowVirtualizer } from '@skyroc/web-ui';何时使用
- 列表或网格数据量很大,直接渲染全部 DOM 会影响性能。
- 每一项高度或宽度可以预估,或可以通过动态测量处理。
- 需要保留滚动容器、滚动位置、滚动到指定索引等底层控制能力。
- 数据量很小或内容高度不可预测且频繁变化时,普通列表通常更简单。
基础列表
VirtualList 只渲染可视区域附近的项目。垂直列表需要设置 height 和 itemSize;横向列表可以设置 horizontal、width 和 itemSize。
<VirtualList data={items} height={300} itemSize={40} renderItem={({ item, index }) => <div>{item.name}</div>} />可变尺寸
itemSize 可以是函数,用于根据索引返回不同的预估尺寸。适合内容高度存在规律差异,但不需要动态测量的场景。
<VirtualList
data={items}
height={300}
itemSize={index => items[index].height}
keyExtractor="id"
renderItem={({ item }) => <div>{item.content}</div>}
/>虚拟网格
VirtualGrid 同时对行和列进行虚拟化。通过 columns 指定总列数,rowHeight 和 columnWidth 提供行高与列宽预估。
<VirtualGrid
data={items}
columns={10}
rowHeight={60}
columnWidth={100}
height={300}
renderCell={(item, rowIndex, colIndex) => <div>{item.content}</div>}
/>实例控制
VirtualList 的 ref 会暴露底层 virtualizer 实例和滚动容器引用,可用于滚动到指定索引、读取可见项等控制场景。
const virtualizerRef = useRef<VirtualizerList>(null);
virtualizerRef.current?.scrollToIndex(5000, { align: 'center' });动态测量
设置 dynamic 后,VirtualList 会把渲染项挂到 measureElement 上,让 TanStack Virtual 在实际 DOM 渲染后测量尺寸。动态测量适合真实高度难以准确预估的内容。
<VirtualList dynamic data={items} height={300} itemSize={48} renderItem={({ item }) => <div>{item.description}</div>} />API
VirtualList
一维虚拟列表组件,支持垂直、横向、固定尺寸、函数式预估尺寸和动态测量。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| data* | 需要虚拟化渲染的数据列表 | item[] | - |
| itemSize* | 项目预估尺寸;垂直列表表示高度,横向列表表示宽度 | number | (index: number) => number | - |
| renderItem* | 项目渲染函数 | (props: VirtualListItem) => ReactNode | - |
| height | 滚动容器高度 | number | string | - |
| width | 滚动容器宽度 | number | string | - |
| horizontal | 是否启用横向虚拟滚动 | boolean | false |
| dynamic | 是否启用动态尺寸测量 | boolean | false |
| keyExtractor | 从数据项中提取稳定 key | property key | (item, index) => string | - |
| onScroll | 滚动偏移变化时触发 | (offset: number) => void | - |
| className | 滚动容器自定义 class | ClassValue | - |
| classNames | 各 slot 的自定义 class(root / inner) | VirtualizerClassNames | - |
| containerProps | 传递给滚动容器 div 的额外属性 | container div props | - |
| ref | 虚拟列表实例引用 | VirtualizerList | - |
VirtualGrid
二维虚拟网格组件,同时虚拟化行与列。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| data* | 需要虚拟化渲染的数据列表 | item[] | - |
| columns* | 总列数 | number | - |
| rowHeight* | 行高预估值或函数 | number | (rowIndex: number) => number | - |
| columnWidth* | 列宽预估值或函数 | number | (colIndex: number) => number | - |
| renderCell* | 单元格渲染函数 | (item, rowIndex: number, colIndex: number) => ReactNode | - |
| height | 滚动容器高度 | number | string | - |
| width | 滚动容器宽度 | number | string | - |
| columnProps | 传递给列 virtualizer 的额外配置 | VirtualizerBaseOptions | - |
| keyExtractor | 从数据项中提取稳定 key | property key | (item, index) => string | - |
| onScroll | 纵向滚动偏移变化时触发 | (offset: number) => void | - |
| className | 滚动容器自定义 class | ClassValue | - |
| classNames | 各 slot 的自定义 class(root / inner) | VirtualizerClassNames | - |
| ref | 虚拟网格实例引用 | VirtualizerGrid | - |
Hooks
useVirtualizer 和 useWindowVirtualizer 直接从 @tanstack/react-virtual re-export,适合完全自定义 DOM 结构或窗口级虚拟滚动场景。
const rowVirtualizer = useVirtualizer({
count: rows.length,
estimateSize: () => 40,
getScrollElement: () => parentRef.current
});类型
VirtualizerClassNames
Virtualizer 各 slot 的自定义 class。
| 字段 | 类型 | 说明 |
|---|---|---|
| root | ClassValue | 滚动容器 class。 |
| inner | ClassValue | 内部占位层 class。 |
VirtualListItem
VirtualList renderItem 函数接收的参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| index | number | 数据项索引。 |
| item | item data | 当前数据项。 |
| virtualItem | virtual item object | TanStack Virtual 当前虚拟项信息。 |
| virtualizer | virtualizer instance | 当前列表 virtualizer 实例。 |
VirtualizerBaseOptions
传递给 TanStack Virtual 的基础配置类型。
| 字段 | 类型 | 说明 |
|---|---|---|
| overscan | number | 可视区域外额外渲染的项目数量。 |
| horizontal | boolean | 是否横向虚拟滚动。 |
| paddingStart | number | 开始位置内边距。 |
| paddingEnd | number | 结束位置内边距。 |
| gap | number | 项目间距。 |
| onChange | (instance, sync) => void | virtualizer 状态变化回调。 |
VirtualizerProps
VirtualList 和 VirtualGrid 共享的基础属性。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | item[] | 数据列表。 |
| height | number | string | 滚动容器高度。 |
| width | number | string | 滚动容器宽度。 |
| keyExtractor | property key | (item, index) => string | 稳定 key 提取函数。 |
| onScroll | (offset: number) => void | 滚动偏移变化回调。 |
| className | ClassValue | 滚动容器 class。 |
| classNames | VirtualizerClassNames | 各 slot 的自定义 class。 |
VirtualListProps
VirtualList 组件属性。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | item[] | 数据列表。 |
| itemSize | number | (index: number) => number | 项目预估尺寸。 |
| renderItem | (props: VirtualListItem) => ReactNode | 项目渲染函数。 |
| dynamic | boolean | 是否启用动态测量。 |
| horizontal | boolean | 是否横向滚动。 |
| ref | VirtualizerList | 实例引用。 |
| ...baseProps | VirtualizerProps | 共享基础属性。 |
VirtualGridProps
VirtualGrid 组件属性。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | item[] | 数据列表。 |
| columns | number | 总列数。 |
| rowHeight | number | (rowIndex: number) => number | 行高预估。 |
| columnWidth | number | (colIndex: number) => number | 列宽预估。 |
| renderCell | (item, rowIndex: number, colIndex: number) => ReactNode | 单元格渲染函数。 |
| columnProps | VirtualizerBaseOptions | 列 virtualizer 配置。 |
| ref | VirtualizerGrid | 实例引用。 |
| ...baseProps | VirtualizerProps | 共享基础属性。 |
VirtualizerList
VirtualList 暴露的实例引用。
| 字段 | 类型 | 说明 |
|---|---|---|
| containerRef | div element | 滚动容器元素。 |
| scrollToIndex | (index: number, options?) => void | 滚动到指定索引。 |
| scrollToOffset | (offset: number, options?) => void | 滚动到指定偏移。 |
| getVirtualItems | () => virtual item object[] | 获取当前虚拟项列表。 |
| getTotalSize | () => number | 获取总占位尺寸。 |
VirtualizerGrid
VirtualGrid 暴露的实例引用。
| 字段 | 类型 | 说明 |
|---|---|---|
| containerRef | div element | 滚动容器元素。 |
| rowVirtualizer | VirtualizerList | 行 virtualizer 实例。 |
| columnVirtualizer | VirtualizerList | 列 virtualizer 实例。 |
| scrollToIndex | (index: number, options?) => void | 滚动到指定行索引。 |
| getVirtualItems | () => virtual item object[] | 获取当前虚拟行列表。 |