介绍

TanStack Virtual 是一个用于在 JS/TS、React、Vue、Svelte、Solid、Lit 和 Angular 中虚拟化长列表元素的无头 UI 工具。它不是一个组件,因此不会为你提供或渲染任何标记或样式。虽然这需要你提供一些标记和样式,但你将保留对样式、设计和实现的 100% 控制权。

Virtualizer(虚拟器)

TanStack Virtual 的核心是 Virtualizer。Virtualizer 可以在垂直(默认)或水平轴上定向,这使得通过将两个轴配置组合在一起来实现垂直、水平甚至网格状虚拟化成为可能。

下面是一个快速示例,展示了如何使用 TanStack Virtual 在 React 中的 div 内虚拟化一个长列表:

tsx
import { useVirtualizer } from '@tanstack/react-virtual';

function App() {
  // 列表的可滚动元素
  const parentRef = React.useRef(null)

  // 虚拟器
  const rowVirtualizer = useVirtualizer({
    count: 10000,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 35,
  })

  return (
    <>
      {/* 列表的可滚动元素 */}
      <div
        ref={parentRef}
        style={{
          height: `400px`,
          overflow: 'auto', // 使其可滚动!
        }}
      >
        {/* 用于容纳所有项目的大的内部元素 */}
        <div
          style={{
            height: `${rowVirtualizer.getTotalSize()}px`,
            width: '100%',
            position: 'relative',
          }}
        >
          {/* 仅显示虚拟器中的可见项目,手动定位使其在视图中 */}
          {rowVirtualizer.getVirtualItems().map((virtualItem) => (
            <div
              key={virtualItem.key}
              style={{
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%',
                height: `${virtualItem.size}px`,
                transform: `translateY(${virtualItem.start}px)`,
              }}
            >
              第 {virtualItem.index} 行
            </div>
          ))}
        </div>
      </div>
    </>
  )
}
import { useVirtualizer } from '@tanstack/react-virtual';

function App() {
  // 列表的可滚动元素
  const parentRef = React.useRef(null)

  // 虚拟器
  const rowVirtualizer = useVirtualizer({
    count: 10000,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 35,
  })

  return (
    <>
      {/* 列表的可滚动元素 */}
      <div
        ref={parentRef}
        style={{
          height: `400px`,
          overflow: 'auto', // 使其可滚动!
        }}
      >
        {/* 用于容纳所有项目的大的内部元素 */}
        <div
          style={{
            height: `${rowVirtualizer.getTotalSize()}px`,
            width: '100%',
            position: 'relative',
          }}
        >
          {/* 仅显示虚拟器中的可见项目,手动定位使其在视图中 */}
          {rowVirtualizer.getVirtualItems().map((virtualItem) => (
            <div
              key={virtualItem.key}
              style={{
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%',
                height: `${virtualItem.size}px`,
                transform: `translateY(${virtualItem.start}px)`,
              }}
            >
              第 {virtualItem.index} 行
            </div>
          ))}
        </div>
      </div>
    </>
  )
}

让我们深入了解更多示例!