Skip to content

vue-virtual-scroller-kit

Виртуальные список, таблица, грид, дерево и select для Vue 3. Динамические высоты строк, измеряемые через ResizeObserver, группировка с анимированным раскрытием/сворачиванием, липкие заголовки, бесконечная прокрутка, навигация с клавиатуры, drag-to-reorder, поддержка RTL и полная поддержка SSR — с единственной peer-зависимостью (Vue 3).

Возможности

  • Динамические высоты строкResizeObserver измеряет каждую строку после рендера; менеджер позиций обновляется за O(log n)
  • VirtualList — плоский список, внешний контейнер прокрутки, page-режим (прокрутка окна), пул переиспользования DOM, восстановление позиции прокрутки, опциональная horizontal-раскладка
  • GroupedVirtualList — сворачиваемые секции с плавной CSS-анимацией раскрытия/сворачивания, опциональный липкий оверлей заголовка группы
  • VirtualTable — нативная <table> с виртуальной прокруткой через строки-распорки, липкий заголовок, зафиксированные левые/правые столбцы, одно- и многоколоночная сортировка, drag-to-resize и drag-to-reorder столбцов, показ/скрытие столбцов, виртуализация столбцов, закреплённые верхние/нижние строки (<thead>/<tfoot>), встроенная ленивая загрузка (onLoadMore / hasMore / isLoading)
  • VirtualGrid — ячейки фиксированной высоты в отзывчивом гриде с автоколонками или фиксированными колонками, либо опциональная динамическая высота на строку
  • VirtualTree — иерархическое раскрытие/сворачивание с ленивой загрузкой дочерних элементов, настраиваемый отступ
  • InfiniteLoader — вызывает onLoadMore у нижнего, верхнего или обоих краёв; сохранение позиции прокрутки при добавлении в начало
  • VirtualSelect — виртуализированный выпадающий список с клиентским или асинхронным/удалённым поиском (с debounce, со слотом загрузки) и навигацией с клавиатуры
  • VirtualScrollbar — темизируемый кастомный оверлей скроллбара, синхронизирующийся с любым из компонентов выше (или любым прокручиваемым элементом)
  • Плавная программная прокруткаscrollTo/scrollToOffset принимают { behavior: 'smooth' }, используя нативный плавный скролл браузера
  • Motion blur — опциональный проп motionBlur применяет CSS-размытие, масштабируемое по скорости, при быстрой прокрутке, снимаемое после остановки
  • Компенсированный якорем reflow — когда строка над вьюпортом измеряется с другой высотой, позиция прокрутки корректируется на ту же дельту, так что видимый контент никогда не прыгает
  • Поддержка RTL — логические CSS-свойства повсюду, плюс нормализация scrollLeft для виртуализации столбцов, горизонтального VirtualList и скроллбара; оберните приложение в dir="rtl", больше ничего не требуется
  • useVirtualScroll — низкоуровневый composable для кастомных контейнеров; возвращает visibleRange, totalHeight, scrollTo; поддерживает горизонтальную ось
  • useVirtualKeyboardNav — стрелки, Home/End, PageUp/PageDown, Enter/Space; подключается к любому виртуальному списку
  • useDraggableList — drag-to-reorder на pointer-событиях с анимированным зазором, «призрачным» элементом, авто-прокруткой, поддержкой отключённых элементов
  • useRowSelection — независимый от структуры данных выбор строк кликом/Shift+клик (одиночный или множественный), сочетается с VirtualList или VirtualTable
  • useVisibilityTracker — события входа/выхода из вьюпорта по ключу на основе настоящего IntersectionObserver, для подсветки пункта навигации/миникарты, пока соответствующая строка на экране
  • PositionManager — дерево отрезков (обновления и запросы префиксных сумм за O(log n)), доступное для продвинутого использования
  • autoColWidths — оценивает ширины столбцов по образцу данных через Canvas measureText; SSR-безопасный fallback
  • SSR-безопасность — первые N строк рендерятся на сервере, гидратация без сдвига разметки
  • Без внешних зависимостей — только Vue 3 как peer-зависимость
  • Tree-shakeable ESM + CJS двойная сборка

Установка

bash
npm install vue-virtual-scroller-kit

Peer-зависимость:

bash
npm install vue@>=3.3

Быстрый старт

vue
<script setup lang="ts">
import { VirtualList } from 'vue-virtual-scroller-kit'

interface Row {
  id: number
  text: string
}

const items: Row[] = Array.from({ length: 100_000 }, (_, i) => ({
  id: i,
  text: `Row ${i + 1}`,
}))
</script>

<template>
  <VirtualList :items="items" :estimated-item-size="48" style="height: 600px">
    <template #default="{ item, index }">
      <div style="padding: 12px 16px; border-bottom: 1px solid #eee">
        {{ index + 1 }}. {{ item.text }}
      </div>
    </template>
  </VirtualList>
</template>