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-kitPeer-зависимость:
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>