tanstack-vue-virtual-skilld
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack/virtual @tanstack/vue-virtual
@tanstack/vue-virtualTanStack/virtual @tanstack/vue-virtual
@tanstack/vue-virtualHeadless UI for virtualizing scrollable elements in Vue
Version: 3.13.21 (Mar 2026)
Deps: @tanstack/virtual-core@3.13.21
Tags: beta: 3.0.0-beta.68 (Oct 2023), latest: 3.13.21 (Mar 2026)
References: Docs — API reference, guides
适用于Vue的可滚动元素虚拟化无头UI组件
版本: 3.13.21(2026年3月)
依赖: @tanstack/virtual-core@3.13.21
标签: beta版:3.0.0-beta.68(2023年10月),最新版:3.13.21(2026年3月)
参考资料: 文档 — API参考、使用指南
API Changes
API变更
This section documents version-specific API changes — prioritize recent major/minor releases.
-
BREAKING:— replaces
useVirtualizerin v3 migration; older positional arguments or v2 option names are no longer supported sourceuseVirtual -
BREAKING:return type — v3
Ref<Virtualizer>returns a VueuseVirtualizerinstead of a raw object; instance methods must be accessed viaRef(e.g.,.value)rowVirtualizer.value.getVirtualItems() -
BREAKING:— replaces
countoption in v3 migration; usingsizewill result in zero items being virtualized sourcesize -
BREAKING:— replaces
getScrollElementoption in v3 migration; must be a function that returns the scrollable element orparentRefsourcenull -
BREAKING:— replaces
measureElementpattern from v2; you must now passmeasureRefto thevirtualizer.value.measureElementattribute and setrefon the element sourcedata-index -
NEW:auto-updates — as of v3.13.13, the virtualizer automatically notifies the framework when the
getTotalSize()option changes, ensuringcountand the UI update correctly without manual workarounds for filtering or search sourcegetTotalSize() -
NEW:— new in v3; allows dividing the list into multiple columns (vertical) or rows (horizontal) to support grid-like or masonry layouts source
lanes -
NEW:— new in v3; specifies the spacing between items in pixels, removing the need for manual margin or padding calculations source
gap -
NEW:— specialized adapter for window-based scrolling; simplifies configuration when the browser window is the scroll container source
useWindowVirtualizer -
NEW:— allows specifying the offset between the scroll container's start and the beginning of the virtualized list; essential for lists preceded by headers source
scrollMargin -
NEW:— built-in support for right-to-left language locales; inverts horizontal scrolling logic when enabled source
isRtl -
NEW:— utilizes the native
useScrollendEventevent where available to resetscrollendstate, falling back to a debounced timer if disabled sourceisScrolling -
NEW:— provides fine-grained control over scroll position adjustments when dynamic items differ from their estimated size source
shouldAdjustScrollPositionOnItemSizeChange -
NEW:— added in v3.13.x; defers ResizeObserver measurement processing to the next animation frame to batch DOM mutations source
useAnimationFrameWithResizeObserver
Also changed: new in v3 · now receives object · adds property · method for manual size overrides · option to pause observers
isScrollingResetDelayrangeExtractorRangeVirtualItemlaneresizeItemenabled本部分记录了各版本的API变更内容,请优先关注近期的大版本/小版本更新。
-
重大变更:— 在v3迁移中替代了
useVirtualizer;旧的位置参数或v2版本的选项名称将不再被支持 来源useVirtual -
重大变更:返回类型 — v3版本的
Ref<Virtualizer>返回Vue的useVirtualizer对象而非原始对象;实例方法必须通过Ref访问(例如:.value)rowVirtualizer.value.getVirtualItems() -
重大变更:— 在v3迁移中替代了
count选项;若使用size将导致虚拟化元素数量为0 来源size -
重大变更:— 在v3迁移中替代了
getScrollElement选项;必须是一个返回可滚动元素或parentRef的函数 来源null -
重大变更:— 替代了v2版本的
measureElement模式;现在你必须将measureRef传递给virtualizer.value.measureElement属性,并在元素上设置ref来源data-index -
新增功能:自动更新 — 从v3.13.13版本开始,当
getTotalSize()选项变更时,虚拟化组件会自动通知框架,确保count和UI能正确更新,无需为过滤或搜索功能手动编写解决方案 来源getTotalSize() -
新增功能:— v3版本新增;允许将列表分为多列(垂直方向)或多行(水平方向),以支持网格状或瀑布流布局 来源
lanes -
新增功能:— v3版本新增;指定元素间的像素间距,无需手动计算外边距或内边距 来源
gap -
新增功能:— 针对基于窗口的滚动场景的专用适配器;当浏览器窗口为滚动容器时,可简化配置 来源
useWindowVirtualizer -
新增功能:— 允许指定滚动容器起始位置与虚拟化列表开头之间的偏移量;对于带有头部的列表至关重要 来源
scrollMargin -
新增功能:— 内置对从右到左语言环境的支持;启用后会反转水平滚动逻辑 来源
isRtl -
新增功能:— 在支持的环境中使用原生
useScrollendEvent事件来重置scrollend状态;若不支持则回退到防抖定时器 来源isScrolling -
新增功能:— 当动态元素与预估尺寸不同时,提供对滚动位置调整的精细控制 来源
shouldAdjustScrollPositionOnItemSizeChange -
新增功能:— v3.13.x版本新增;将ResizeObserver的测量处理延迟到下一动画帧,以批量处理DOM变更 来源
useAnimationFrameWithResizeObserver
其他变更: 在v3版本新增 · 现在接收对象 · 新增属性 · 方法用于手动覆盖尺寸 · 选项用于暂停观察者
isScrollingResetDelayrangeExtractorRangeVirtualItemlaneresizeItemenabledBest Practices
最佳实践
- Account for in absolute positioning — when using a shared scroll container with static headers, subtract the margin from the item's start position to maintain correct layout source
scrollMargin
vue
<script setup>
const rowVirtualizer = useVirtualizer({
count: 1000,
scrollMargin: 100, // Height of header
// ...
})
</script>
<template>
<div v-for="item in rowVirtualizer.getVirtualItems()" :key="item.key"
:style="{
transform: `translateY(${item.start - rowVirtualizer.options.scrollMargin}px)`
}"
>
{{ item.index }}
</div>
</template>-
Overestimatefor dynamic elements — providing a "maximum likely" size prevents the scrollbar from jumping and items from "resetting" their position when scrolling upwards into unmeasured territory source
estimateSize -
Implementfor chat/messaging UIs — use this callback to control scroll adjustments when prepending items, preventing visual jumps as new elements are measured source
shouldAdjustScrollPositionOnItemSizeChange -
Attachwhen using
data-index— the virtualizer requires this attribute on the measured DOM element to correctly map the size back to the item's internal state sourcemeasureElement
vue
<div
v-for="item in virtualizer.getVirtualItems()"
:key="item.key"
:data-index="item.index"
:ref="virtualizer.measureElement"
>
{{ item.index }}
</div>-
Pass configuration viaor
computed— the Vue adapter'sRefwatch-triggersuseVirtualizerautomatically, allowing the instance to reactively updatesetOptionsorcountwithout manual re-instantiationoverscan -
Avoidfor performance — native
useAnimationFrameWithResizeObserveris already batched; enabling this adds a ~16ms delay that can cause visual flickering or stale measurements during fast scrolls sourceResizeObserver -
Provide a stablefor persistent state — using a unique identifier (like a database ID) instead of the default index ensures that item state (focus, internal refs) is preserved during reorders or filtering source
getItemKey -
Wrap initialin
scrollToIndex— for "scroll-to-bottom" initialization (e.g. chat), deferring the scroll ensures the DOM is rendered and initial measurements are processed by the virtualizer sourcerequestAnimationFrame -
Use built-inover manual CSS margins — the
gapoption ensures the virtualizer accounts for item spacing in its internalgapcalculation, which manual margins do not sourcegetTotalSize() -
Pause observers with— instead of unmounting the virtualizer, toggle the
enabled: falseoption to pause monitoring (e.g., when a tab is hidden). This preserves existing measurements while saving CPU cycles sourceenabled
- 绝对定位时需考虑— 当使用带有静态头部的共享滚动容器时,需从元素的起始位置中减去该边距以保持布局正确 来源
scrollMargin
vue
<script setup>
const rowVirtualizer = useVirtualizer({
count: 1000,
scrollMargin: 100, // 头部高度
// ...
})
</script>
<template>
<div v-for="item in rowVirtualizer.getVirtualItems()" :key="item.key"
:style="{
transform: `translateY(${item.start - rowVirtualizer.options.scrollMargin}px)`
}"
>
{{ item.index }}
</div>
</template>-
为动态元素高估— 提供一个“最大可能”的尺寸可防止滚动条跳动,以及向上滚动到未测量区域时元素位置“重置”的问题 来源
estimateSize -
为聊天/消息类UI实现— 使用此回调函数控制添加前置元素时的滚动调整,避免新元素测量时出现视觉跳动 来源
shouldAdjustScrollPositionOnItemSizeChange -
使用时附加
measureElement— 虚拟化组件需要被测DOM元素上的该属性,才能将尺寸正确映射到元素的内部状态 来源data-index
vue
<div
v-for="item in virtualizer.getVirtualItems()"
:key="item.key"
:data-index="item.index"
:ref="virtualizer.measureElement"
>
{{ item.index }}
</div>-
通过或
computed传递配置 — Vue适配器的Ref会自动监听并触发useVirtualizer,允许实例响应式更新setOptions或count,无需手动重新实例化overscan -
避免启用以提升性能 — 原生
useAnimationFrameWithResizeObserver已支持批量处理;启用此选项会增加约16ms延迟,可能导致快速滚动时出现视觉闪烁或测量数据过期 来源ResizeObserver -
提供稳定的以保持状态持久化 — 使用唯一标识符(如数据库ID)而非默认索引,确保元素状态(焦点、内部refs)在重新排序或过滤时得以保留 来源
getItemKey -
将初始包装在
scrollToIndex中 — 对于“滚动到底部”的初始化场景(如聊天),延迟滚动可确保DOM已渲染,且虚拟化组件已完成初始测量 来源requestAnimationFrame -
使用内置替代手动CSS外边距 —
gap选项可确保虚拟化组件在内部gap计算中考虑元素间距,而手动外边距则无法实现这一点 来源getTotalSize() -
使用暂停观察者 — 无需卸载虚拟化组件,只需切换
enabled: false选项即可暂停监控(例如标签页隐藏时)。这样既能保留现有测量数据,又能节省CPU资源 来源enabled