Components/VirtualList

VirtualList

A fixed-row-height list that renders only the visible rows.

VerifiedSince 0.3.4

Usage

Basic

itemHeight fixes the row height and height sets the viewport.

Loading demo...

Stable Item Keys

<template>
  <TxVirtualList :items="users" :item-height="44" height="360px" item-key="id">
    <template #item="{ item }">
      <UserRow :user="item" />
    </template>
  </TxVirtualList>
</template>

Imperative Scrolling

<script setup lang="ts">
const listRef = ref()

function jumpToLatest() {
  listRef.value?.scrollToBottom()
}
</script>

<template>
  <TxButton @click="jumpToLatest">Latest</TxButton>
  <TxVirtualList ref="listRef" :items="logs" :item-height="32" :height="400" />
</template>

Best Practices

  • Use it only for fixed-height rows; variable heights throw off the scroll math.
  • Point itemKey at a stable id for object lists; index keys suit immutable arrays only.
  • Keep overscan modest: more rows scroll smoother but cost more DOM work.
  • Put spacing inside the fixed-height row, not as vertical margins around it.
  • Use scroll for analytics or lazy-load triggers, not per-frame heavy work.

API Reference

Props

PropTypeDefaultDescription
itemsT[][]The full data set.
itemHeightnumberrequiredFixed row height in px; every row must match it.
heightnumber | string320Scroll container height; numbers become px.
overscannumber4Extra rows rendered before and after the viewport.
itemKeykeyof T | (item: T, index: number) => string | numberindexRow key: a field name or function; a missing field falls back to its index in items.

Events

EventPayloadDescription
scroll{ scrollTop: number, startIndex: number, endIndex: number }Fires after a scroll updates the visible range.

Slots

SlotPropsDescription
item{ item: T, index: number }Renders each visible item; defaults to item as text.

Exposed Methods

MethodSignatureDescription
scrollToIndex(index: number) => voidScrolls to Math.max(0, index) * itemHeight; indexes past the last item aren't clamped.
scrollToTop() => voidScrolls to the top.
scrollToBottom() => voidScrolls to max(0, totalHeight - viewHeight).

Overview

  • Every row is exactly itemHeight px tall; a numeric height becomes px, and a string is applied as-is.
  • Numeric, px, and bare numeric string heights count immediately; %, vh, vw, rem, and em wait for the mounted clientHeight, so give SSR or hidden containers a concrete height.
  • With ResizeObserver available, container resizes update the viewport height.
  • The visible range runs from floor(scrollTop / itemHeight) - overscan to the viewport's end plus overscan, clamped between 0 and items.length.
  • The spacer is items.length * itemHeight tall, and visible items shift by startIndex * itemHeight.
  • The container and rows carry no role or aria-*. For list semantics, wrap them with role="list" / role="listitem" and set aria-setsize / aria-posinset from the real total and absolute indexes.

Technologies

  • Source: packages/tuffex/packages/components/src/virtual-list/.
查看源码
packages/tuffex/packages/components/src/virtual-list/index.ts