Skip to content

参考

基于 TanStack Virtual v3 / react-window v2 / vue-virtual-scroller v3 官方文档编写

速查

  • 三库版本(2026-07):TanStack Virtual v3.14.x | react-window v2.2.x | vue-virtual-scroller v3.0.x
  • TanStack 核心useVirtualizer({ count, getScrollElement, estimateSize, overscan?, getItemKey? })getVirtualItems() / getTotalSize() / scrollToIndex()
  • react-window v2 核心<List rowCount rowHeight rowComponent rowProps height width /> + useDynamicRowHeight
  • vue-virtual-scroller 核心<RecycleScroller items itemSize keyField buffer /><DynamicScroller items minItemSize> + <DynamicScrollerItem size-dependencies />
  • 共同 CSS 套路:父 overflow:auto + 固定高 + position:relative;子 position:absolute + transform:translateY(start)
  • 键值复用getItemKey / keyField 必用稳定 id,不要用 index
  • 动态测量:TanStack measureElement + estimateSize 取大;react-window useDynamicRowHeight;vue-virtual-scroller DynamicScrollerItem + size-dependencies
  • 反转流:TanStack v3 anchorTo:'end' + followOnAppend + scrollEndThreshold

TanStack Virtual API 速查

useVirtualizer 选项

选项类型默认说明
countnumber总条数(必填)
getScrollElement() => HTMLElement | null滚动父元素(必填)
estimateSize() => number预估行高(必填,动态取最大值)
overscannumber1上下缓冲行数
horizontalbooleanfalse横向滚动
getItemKey(i) => Keyindex稳定键(动态 / 增删必填)
gapnumber0行间距
lanesnumber1多列 / 瀑布
paddingStart / paddingEndnumber0内边距
scrollMarginnumber0滚动容器内嵌套时的偏移
initialRect{ width, height }SSR / 首测前初始尺寸
initialOffset{ top, left }初始滚动位置
isRtlbooleanfalseRTL 布局
rangeExtractor(range) => number[]自定义渲染范围(粘性 header 等)
useCachedMeasurementsbooleanfalsedisplay:none 测量归零
isScrollingResetDelaynumber150isScrolling 复位延迟(ms)
useScrollendEventboolean用原生 scrollend 事件

TanStack v3 反转流 / 聊天相关

选项说明
anchorTo'start' | 'end',聊天 / 日志反转流用 'end'
followOnAppend追加新项时是否自动跟随到底
scrollEndThreshold距底多少 px 内才算「在底端」
shouldAdjustScrollPositionOnItemSizeChange控制向上滚动时是否纠正位移

TanStack React 特有

选项 / 方法说明
useWindowVirtualizer(options)用浏览器 window 作滚动元素
useFlushSync(默认 true)React 19 滚动告警时可关
directDomUpdates跳过 React 重渲染,直接写 DOM(高频更新)
directDomUpdatesMode'transform' | 'position',定位策略

Virtualizer 实例方法

方法用途
getVirtualItems()当前应渲染的虚拟项数组
getTotalSize()列表总尺寸
scrollToIndex(i, { align, behavior })跳到第 i 项
scrollToOffset(px, { align, behavior })按像素跳
scrollToEnd()跳到底部
getDistanceFromEnd() / isAtEnd()距底距离 / 是否到底(下拉加载用)
measure()整体重测
measureElement(node)ref 回调,挂 ResizeObserver
resizeItem(i, size)手动指定尺寸
takeSnapshot()拍测量快照(恢复滚动位置)

框架适配器包

框架
@tanstack/react-virtualReact
@tanstack/vue-virtualVue 3
@tanstack/svelte-virtualSvelte
@tanstack/solid-virtualSolid
@tanstack/lit-virtualLit
@tanstack/angular-virtualAngular
@tanstack/marko-virtualMarko

react-window API 速查

v2:List 与 Grid 必填 props

Prop类型说明
rowComponent / cellComponentComponentType渲染单行 / 单元格的组件
rowCount / columnCountnumber行 / 列数
rowHeight / columnWidthnumber | pct | fn | DynamicCache行高 / 列宽
rowProps / cellPropsobject透传给 rowComponent 的额外数据(必填,可为 {}

v2 可选 props

Prop默认说明
overscanCount双向预渲染行数
defaultHeight / defaultWidthSSR 初始尺寸
tagNamediv容器标签
onRowsRendered / onCellsRendered渲染回调
onResize容器尺寸变化回调

v2 hooks

Hook用途
useDynamicRowHeight()动态行高测量缓存,传给 rowHeight
useListRef() / useGridRef()TS 友好的 ref,拿到 imperative API
useListCallbackRef()回调式 ref

v1:FixedSize / Variable 系列(旧项目)

组件用途
FixedSizeList等高一维列表
VariableSizeList变高一维(itemSize 函数 + 手动 resetAfterIndex
FixedSizeGrid / VariableSizeGrid等高 / 变高二维

v1 仍维护但不再拿新特性;v1 文档在 react-window-v1.vercel.app,与 v2 共存。

vue-virtual-scroller API 速查

RecycleScroller(等高 / 复用 DOM)

Prop默认说明
items列表数据
itemSize等高行高
keyField'id'稳定键字段(或 (item, index) => key
minItemSize最小行高
sizeField'size'从 item 字段读尺寸
buffer200上下缓冲像素(对应 overscan)
prerender0首屏预渲染条数(SSR 友好)
pageModefalse用 window 作滚动元素
listClass / listTag容器样式 / 标签
itemClass / itemTag项样式 / 标签

DynamicScroller(动态测量)

Prop默认说明
items列表数据
minItemSize最小行高(测量基准,必填)
keyField'id'稳定键字段
buffer200上下缓冲像素

DynamicScrollerItem(必须包装在 DynamicScroller 内)

Prop说明
item当前数据项
active来自作用域插槽(是否在可见区)
data-index序号
size-dependencies影响尺寸的字段数组(如 [item.title, item.body]

Headless Composables(Vue 3.3+ 泛型)

Composable用途
useRecycleScroller<T>()RecycleScroller 的 headless 版本
useDynamicScroller<T>()DynamicScroller 的 headless 版本
useWindowScroller<T>()页面级滚动的 headless 版本
useTableColumnWidths()<table> 自定义布局的列宽测量

安装注意事项

  • 仅支持 Vue 3.3+(Vue 2 用 v1 分支)
  • ESM only,没有 CommonJS 入口
  • 必须 import 'vue-virtual-scroller/index.css',否则定位错乱

共同必备 CSS 套路

css
/* 父容器:必须固定高度 + overflow:auto + position:relative */
.scroll-parent {
  height: 480px;
  overflow: auto;
  position: relative;
}

/* 内部占位:getTotalSize() 撑出总高 */
.scroll-inner {
  position: relative;
  width: 100%;
}

/* 子项:绝对定位 + transform 落位 */
.scroll-item {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  /* transform: translateY(...) 由 JS 内联写入 */
}

TanStack 默认推荐 transform: translateY();react-window 通过 style prop 透传;vue-virtual-scroller 内部已处理。无论哪种实现,几何模型一致。

版本现状(2026-07)

当前主版本重要变化
TanStack Virtualv3(3.14.x)跨框架统一核心;新增 anchorTo / followOnAppend / directDomUpdates / takeSnapshot,面向聊天 / 反转流与高频更新
react-windowv2(2.2.x)ResizeObserver 基线、API 围绕 List / Grid 重构、自动 memo 与自动 sizing、双向 overscan;v1 仍维护兼容
vue-virtual-scrollerv3(3.0.x,2026-05 发布 3.0.4)仅 Vue 3.3+、ESM only、提供组件式与 headless composables 双 API;Vue 2 用 v1 分支

三者均处于活跃维护状态。新项目按框架选其一即可。

选型决策树

text
列表 DOM 节点数 > 500~1000 且首屏 / 滚动卡顿?
├── 否 → 直接 v-for / map,不虚拟化
└── 是
    ├── React 项目
    │   ├── 需要最大控制力 / 跨框架迁移 → TanStack Virtual
    │   └── 想要最少样板、开箱即用 → react-window v2
    ├── Vue 3.3+ 项目
    │   ├── 需要最大控制力 / 跨框架迁移 → TanStack Virtual
    │   └── 想要组件式、自动测量 → vue-virtual-scroller
    └── 其他框架(Svelte/Solid/Lit/Angular…) → TanStack Virtual(唯一广覆盖选项)

官方资源