Lzh on GitHub

Virtualizer 类是 TanStack Virtual 的核心。虚拟器实例通常由您的框架适配器为您创建,但您会直接接收到该虚拟器。

export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
  constructor(options: VirtualizerOptions<TScrollElement, TItemElement>)
}

必需选项 (Required Options)

count

count: number

要虚拟化的项目总数。

getScrollElement

getScrollElement: () => TScrollElement

一个函数,返回虚拟器的可滚动元素。如果元素尚未可用,它可以返回 null

estimateSize

estimateSize: (index: number) => number

如果您要动态测量元素,建议估计项目的最大可能尺寸(宽度/高度,在舒适范围内)。这将确保平滑滚动等功能有更好的机会正常工作。

此函数会传入每个项目的索引,并应返回每个项目的 实际尺寸(或者如果您将使用 virtualItem.measureElement 动态测量项目,则返回 估计尺寸)。此测量应根据虚拟器的方向返回宽度或高度。

可选选项 (Optional Options)

enabled

enabled?: boolean

设置为 false 以禁用 scrollElement 观察器并重置虚拟器的状态。

debug

debug?: boolean

设置为 true 以启用调试日志。

initialRect

initialRect?: Rect

scrollElement 的初始 Rect。这主要在您需要在 SSR 环境中运行虚拟器时有用,否则 initialRect 将在挂载时由 observeElementRect 实现计算。

onChange

onChange?: (instance: Virtualizer<TScrollElement, TItemElement>, sync: boolean) => void

当虚拟器内部状态改变时触发的回调函数。它会传入虚拟器实例和 sync 参数。

sync 参数指示滚动是否正在进行中。当滚动进行时为 true,当滚动停止或执行其他操作(如调整大小)时为 false

overscan

overscan?: number

在可见区域上方和下方渲染的项目数量。增加此数字会增加渲染虚拟器所需的时间,但可能会降低在滚动时看到虚拟器顶部和底部渲染缓慢的空白项目的可能性。默认值为 1

horizontal

horizontal?: boolean

如果您的虚拟器是水平方向的,请将其设置为 true

paddingStart

paddingStart?: number

应用于虚拟器起始端的内边距,以像素为单位。

paddingEnd

paddingEnd?: number

应用于虚拟器结束端的内边距,以像素为单位。

scrollPaddingStart

scrollPaddingStart?: number

滚动到元素时应用于虚拟器起始端的内边距,以像素为单位。

scrollPaddingEnd

scrollPaddingEnd?: number

滚动到元素时应用于虚拟器结束端的内边距,以像素为单位。

initialOffset

initialOffset?: number | (() => number)

应用于虚拟器的初始偏移量。这通常仅在您在 SSR 环境中渲染虚拟器时有用。

getItemKey

getItemKey?: (index: number) => Key

此函数会传入每个项目的索引,并应返回该项目的唯一键。此函数的默认功能是返回项目的索引,但如果可能,您应该覆盖此函数以返回整个集合中每个项目的唯一标识符。此函数应被记忆化以防止不必要的重新渲染。

rangeExtractor

rangeExtractor?: (range: Range) => number[]

此函数接收可见范围索引,并应返回要渲染的索引数组。如果您需要手动从虚拟器中添加或删除项目,而不考虑可见范围,例如渲染粘性项目、标题、页脚等,这非常有用。默认的范围提取器实现将返回可见范围索引,并作为 defaultRangeExtractor 导出。

scrollToFn

scrollToFn?: (
  offset: number,
  options: { adjustments?: number; behavior?: 'auto' | 'smooth' },
  instance: Virtualizer<TScrollElement, TItemElement>,
) => void

一个可选函数,如果提供,则应实现 scrollElement 的滚动行为。它将使用以下参数调用:

  • 要滚动到的 offset(以像素为单位)。
  • 一个对象,指示估计尺寸和实际尺寸之间是否存在差异(adjustments)和/或滚动是否以平滑动画(behavior)调用。
  • 虚拟器实例本身。

请注意,内置的滚动实现作为 elementScrollwindowScroll 导出,它们由 useVirtualizeruseWindowVirtualizer 等框架适配器函数自动配置。

尝试将 smoothScroll 与动态测量元素一起使用将不起作用。

observeElementRect

observeElementRect: (
  instance: Virtualizer<TScrollElement, TItemElement>,
  cb: (rect: Rect) => void,
) => void | (() => void)

一个可选函数,如果提供,当 scrollElement 改变时会调用,并且应该实现 scrollElementRect(一个具有 widthheight 的对象)的初始测量和持续监控。它会传入实例(通过 instance.scrollElement 也可以访问 scrollElement)。内置实现作为 observeElementRectobserveWindowRect 导出,它们由您的框架适配器导出的函数(如 useVirtualizeruseWindowVirtualizer)自动为您配置。

observeElementOffset

observeElementOffset: (
    instance: Virtualizer<TScrollElement, TItemElement>,
    cb: (offset: number) => void,
  ) => void | (() => void)

一个可选函数,如果提供,当 scrollElement 改变时会调用,并且应该实现 scrollElement 滚动偏移量(一个数字)的初始测量和持续监控。它会传入实例(通过 instance.scrollElement 也可以访问 scrollElement)。内置实现作为 observeElementOffsetobserveWindowOffset 导出,它们由您的框架适配器导出的函数(如 useVirtualizeruseWindowVirtualizer)自动为您配置。

measureElement

measureElement?: (
  element: TItemElement,
  entry: ResizeObserverEntry | undefined,
  instance: Virtualizer<TScrollElement, TItemElement>,
) => number

当虚拟器需要动态测量项目尺寸(宽度或高度)时,会调用此可选函数。

您可以使用 instance.options.horizontal 来确定应该测量项目的宽度还是高度。

scrollMargin

scrollMargin?: number

使用此选项,您可以指定滚动偏移量的起始位置。通常,此值表示滚动元素的开头与列表的开头之间的空间。这在常见场景中特别有用,例如当您在窗口虚拟器前面有一个标题或在一个滚动元素中使用了多个虚拟器时。如果您使用元素的绝对定位,则应在 CSS transform 中考虑 scrollMargin

transform: `translateY(${
  virtualRow.start - rowVirtualizer.options.scrollMargin
}px)`

为了动态测量 scrollMargin 的值,您可以使用 getBoundingClientRect()ResizeObserver。当您的虚拟列表上方项目的高度可能发生变化时,这很有帮助。

gap

gap?: number

此选项允许您设置虚拟化列表中项目之间的间距。它特别适用于在项目之间保持一致的视觉分离,而无需手动调整每个项目的边距或内边距。该值以像素为单位指定。

lanes

lanes: number

列表被划分的车道数(垂直列表的列数或水平列表的行数)。

isScrollingResetDelay

isScrollingResetDelay: number

此选项允许您指定在最后一次滚动事件之后等待多长时间,然后重置 isScrolling 实例属性。默认值为 150 毫秒。

此选项的实现是为了解决跨不同浏览器处理滚动行为的可靠机制需求。直到所有浏览器统一支持 scrollEnd 事件。

useScrollendEvent

useScrollendEvent: boolean

确定是否使用原生的 scrollend 事件来检测滚动何时停止。如果设置为 false,则在 isScrollingResetDelay 毫秒后使用去抖动的回退来重置 isScrolling 实例属性。默认值为 false

此选项的实现是为了解决跨不同浏览器处理滚动行为的可靠机制需求。直到所有浏览器统一支持 scrollEnd 事件。

isRtl

isRtl: boolean

是否反转水平滚动以支持从右到左的语言环境。

useAnimationFrameWithResizeObserver

useAnimationFrameWithResizeObserver: boolean

此选项启用将 ResizeObserver 测量包装在 requestAnimationFrame 中,以实现更平滑的更新并减少布局抖动。默认值为 false

它有助于防止“ResizeObserver loop completed with undelivered notifications”错误,确保测量与渲染周期对齐。这可以提高性能并减少 UI 抖动,尤其是在动态调整元素大小时。但是,由于 ResizeObserver 已经异步运行,添加 requestAnimationFrame 可能会在测量中引入轻微延迟,这在某些情况下可能会很明显。如果调整大小操作是轻量级的且不会导致回流,则启用此选项可能不会带来显著优势。

Virtualizer 实例 (Virtualizer Instance)

以下属性和方法在虚拟器实例上可用:

options

options: readonly Required<VirtualizerOptions<TScrollElement, TItemElement>>

虚拟器当前选项。此属性通过您的框架适配器更新,并且是只读的。

scrollElement

scrollElement: readonly TScrollElement | null

虚拟器当前滚动元素。此属性通过您的框架适配器更新,并且是只读的。

getVirtualItems

type getVirtualItems = () => VirtualItem[]

返回虚拟器当前状态的虚拟项目。

getVirtualIndexes

type getVirtualIndexes = () => number[]

返回虚拟器当前状态的虚拟行索引。

scrollToOffset

scrollToOffset: (
  toOffset: number,
  options?: {
    align?: 'start' | 'center' | 'end' | 'auto',
    behavior?: 'auto' | 'smooth'
  }
) => void

将虚拟器滚动到提供的像素偏移量。您可以选择传递对齐模式以将滚动锚定到 scrollElement 的特定部分。

scrollToIndex

scrollToIndex: (
  index: number,
  options?: {
    align?: 'start' | 'center' | 'end' | 'auto',
    behavior?: 'auto' | 'smooth'
  }
) => void

将虚拟器滚动到提供的索引的项目。您可以选择传递对齐模式以将滚动锚定到 scrollElement 的特定部分。

getTotalSize

getTotalSize: () => number

返回虚拟化项目的总大小(以像素为单位)。如果您选择在渲染时动态测量元素,此测量值将逐渐变化。

measure

measure: () => void

重置任何之前的项目测量。

measureElement

measureElement: (el: TItemElement | null) => void

使用您配置的 measureElement 虚拟器选项测量元素。当组件渲染时(例如使用 React 的 ref 回调 prop),您有责任在您的虚拟器标记中调用此函数,并添加 data-index

 <div
  key={virtualRow.key}
  data-index={virtualRow.index}
  ref={virtualizer.measureElement}
  style={...}
>...</div>

默认情况下,measureElement 虚拟器选项配置为使用 getBoundingClientRect() 测量元素。

resizeItem

resizeItem: (index: number, size: number) => void

手动更改虚拟化项目的尺寸。使用此函数手动设置此索引的计算尺寸。在使用一些自定义变形过渡且您预先知道变形项目尺寸的情况下很有用。

您还可以将此方法与节流的 ResizeObserver 一起使用,而不是 Virtualizer.measureElement 以减少重新渲染。

请注意,当使用 Virtualizer.measureElement 监控该项目时手动更改项目尺寸,将导致不可预测的行为,因为 Virtualizer.measureElement 也在更改尺寸。但是,您可以在同一个虚拟器实例中,但在不同的项目索引上使用 resizeItemmeasureElement 中的一个。

scrollRect

scrollRect: Rect

滚动元素的当前 Rect

shouldAdjustScrollPositionOnItemSizeChange

shouldAdjustScrollPositionOnItemSizeChange: undefined | ((item: VirtualItem, delta: number, instance: Virtualizer<TScrollElement, TItemElement>) => boolean)

shouldAdjustScrollPositionOnItemSizeChange 方法允许对动态渲染项目尺寸与估计尺寸不同时滚动位置的调整进行细粒度控制。当在列表中间跳转并向后滚动时,新元素可能具有与最初估计尺寸不同的尺寸。这种差异会导致后续项目移位,可能会中断用户的滚动体验,尤其是在向后导航列表时。

isScrolling

isScrolling: boolean

布尔标志,指示列表当前是否正在滚动。

scrollDirection

scrollDirection: 'forward' | 'backward' | null

此选项指示滚动方向,可能的值为向下滚动时为 'forward',向上滚动时为 'backward'。当没有活动滚动时,该值设置为 null

scrollOffset

scrollOffset: number

此选项表示沿滚动轴的当前滚动位置。它以像素为单位从可滚动区域的起点测量。