Виртуальный скролл v-virtual-scroll

v-virtual-scroll — это компонент Vuetify, предназначенный для оптимизации отображения больших списков данных. Основная идея заключается в рендеринге только тех элементов, которые видимы пользователю в текущей области просмотра, что значительно снижает нагрузку на DOM и улучшает производительность.

Подключение и базовая структура

Для использования v-virtual-scroll необходимо, чтобы проект был настроен с Vuetify версии 2.x или 3.x. Компонент обычно оборачивает массив данных и использует слот для генерации элементов списка:

<v-virtual-scroll
  :items="items"
  item-height="48"
>
  <template v-slot="{ item }">
    <v-list-item>
      <v-list-item-content>
        <v-list-item-title>{{ item.name }}</v-list-item-title>
      </v-list-item-content>
    </v-list-item>
  </template>
</v-virtual-scroll>
  • :items — массив объектов, которые необходимо отобразить.
  • item-height — фиксированная высота элемента списка. Этот параметр критически важен для правильного расчёта виртуального скролла.

Управление производительностью

Ключевой момент: при больших объёмах данных крайне важно использовать фиксированную высоту элементов. Если элементы имеют динамическую высоту, производительность снижается, так как компонент вынужден пересчитывать позиции элементов при каждом изменении.

Для массивов более 10 000 элементов рекомендуется использовать ленивую подгрузку данных через события update:visible, что позволяет загружать и рендерить элементы только по мере прокрутки:

<v-virtual-scroll
  :items="visibleItems"
  item-height="48"
  @update:visible="loadMore"
>

Метод loadMore может подгружать данные из API и добавлять их к массиву visibleItems.

Настройка прокрутки

v-virtual-scroll предоставляет несколько ключевых свойств для управления прокруткой и визуализацией:

  • height — задаёт высоту контейнера скролла. Если не задано, компонент занимает всю доступную высоту родителя.
  • start-index — позволяет задать индекс элемента, с которого должна начинаться видимая область.
  • buffer — количество элементов, рендерящихся за пределами видимой области, чтобы избежать мерцания при прокрутке.

Пример:

<v-virtual-scroll
  :items="items"
  item-height="50"
  height="400"
  :buffer="5"
  :start-index="0"
>

Слоты и кастомизация элементов

Компонент полностью поддерживает слоты, что позволяет создавать сложные элементы списка с изображениями, кнопками, чекбоксами и другими интерактивными компонентами:

<v-virtual-scroll :items="items" item-height="60">
  <template v-slot="{ item, index }">
    <v-list-item :key="item.id">
      <v-list-item-avatar>
        <img :src="item.avatar" />
      </v-list-item-avatar>
      <v-list-item-content>
        <v-list-item-title>{{ item.name }}</v-list-item-title>
        <v-list-item-subtitle>{{ item.email }}</v-list-item-subtitle>
      </v-list-item-content>
      <v-list-item-action>
        <v-btn icon @click="editItem(item)">edit</v-btn>
      </v-list-item-action>
    </v-list-item>
  </template>
</v-virtual-scroll>

Использование index в слоте позволяет нумеровать элементы или реализовывать дополнительные условия отображения.

Поддержка динамических данных

Для реактивных массивов v-virtual-scroll автоматически обновляет видимую область при добавлении или удалении элементов. Важно обеспечить, чтобы массив был реактивным, например через ref или reactive в Vue 3:

const items = ref([]);
fetchData().then(data => {
  items.value = data;
});

Добавление новых элементов к items.value автоматически обновит виртуальный скролл.

Интеграция с фильтрацией и сортировкой

Компонент совместим с реактивной фильтрацией и сортировкой:

computed: {
  filteredItems() {
    return this.items.filter(item => item.active).sort((a, b) => a.name.localeCompare(b.name));
  }
}

Затем filteredItems передаётся в v-virtual-scroll вместо исходного массива:

<v-virtual-scroll :items="filteredItems" item-height="50">

Важные рекомендации

  • Всегда задавать фиксированную высоту элементов для предсказуемой производительности.
  • Использовать buffer для предотвращения мерцания при быстрой прокрутке.
  • При работе с очень большими списками (десятки тысяч элементов) сочетать виртуальный скролл с ленивой загрузкой данных.
  • Для сложных компонентов внутри слота оптимизировать внутренние рендеры, чтобы минимизировать нагрузку на DOM.

v-virtual-scroll позволяет создавать высокопроизводительные, масштабируемые интерфейсы списков в Vuetify, сохраняя плавность прокрутки и экономя ресурсы браузера при работе с большими массивами данных.