Skip to content

Кастомная виртуализация

useVirtualScroll() — низкоуровневый composable, на котором работают все компоненты. Используйте его, когда нужно построить кастомный виртуальный контейнер.

ts
type SizeProvider = number | ((index: number) => number)

function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualScrollReturn

Опции

itemCount

number | Ref<number>

Общее число элементов.

estimatedItemSize

SizeProvider | Ref<SizeProvider> · по умолчанию: 50

Оценочная высота элемента: число или (index) => number. Ref вызывает полную перестройку при изменении.

overscan

number · по умолчанию: 3

Дополнительные элементы, рендерящиеся вне вьюпорта.

getScrollElement

() => HTMLElement | null

Возвращает контейнер прокрутки.

pageMode

boolean · по умолчанию: false

Использовать window как контейнер прокрутки. Считывается один раз, не реактивно — см. примечание ниже.

horizontal

boolean · по умолчанию: false

Виртуализировать scrollLeft/clientWidth вместо scrollTop/clientHeight, RTL-безопасно через normalizeScrollLeft. Считывается один раз, не реактивно — см. примечание ниже.

motionBlur

boolean · по умолчанию: false

Отслеживать скорость прокрутки и предоставлять её как blurAmount (px). По умолчанию выключено — нулевая стоимость при отключении.

pageMode и horizontal считываются из options один раз при настройке composable — изменение их на живом инстансе не даёт эффекта. Если нужно переключить оси во время выполнения, перемонтируйте компонент, вызывающий useVirtualScroll (например, через :key).

Возвращаемое значение

visibleRange

Readonly<Ref<VisibleRange>>

{ start, end } — индексы первого и последнего видимых элементов.

totalHeight

Readonly<Ref<number>>

Общий прокручиваемый размер в px по оси прокрутки (высота, либо ширина при horizontal).

offsetTop

(index: number) => number

Пиксельное смещение элемента по индексу вдоль оси прокрутки (top, либо left при horizontal).

scrollTo

(index, align?, options?) => void

Прокрутить к элементу ('start' | 'center' | 'end' | 'auto'). options.behavior'auto' (по умолчанию, мгновенно) или 'smooth'.

scrollToOffset

(offset: number, options?) => void

Прокрутить к сырому пиксельному смещению. Тот же options.behavior.

measureItem

(index, height) => void

Сообщить измеренную высоту строки.

handleScroll

() => void

Вручную запустить пересчёт видимого диапазона.

blurAmount

Readonly<Ref<number>>

Текущий радиус motion-blur в px. Всегда 0, если опция motionBlur не включена.

Пример

vue
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useVirtualScroll } from 'vue-virtual-scroller-kit'

const ITEMS = Array.from({ length: 50_000 }, (_, i) => `Item ${i + 1}`)
const containerRef = ref<HTMLElement | null>(null)

const { visibleRange, totalHeight, offsetTop } = useVirtualScroll({
  itemCount: ITEMS.length,
  estimatedItemSize: 40,
  getScrollElement: () => containerRef.value,
})
</script>

<template>
  <div ref="containerRef" style="height: 500px; overflow-y: auto; position: relative">
    <div :style="{ height: `${totalHeight}px`, position: 'relative' }">
      <div
        v-for="i in visibleRange.end - visibleRange.start + 1"
        :key="visibleRange.start + i - 1"
        :style="{
          position: 'absolute',
          top: `${offsetTop(visibleRange.start + i - 1)}px`,
          width: '100%',
          height: '40px',
        }"
      >
        {{ ITEMS[visibleRange.start + i - 1] }}
      </div>
    </div>
  </div>
</template>