QVirtualScroll виртуализация списков

QVirtualScroll — компонент библиотеки Quasar, предназначенный для эффективной работы с длинными списками данных. Его основная задача — виртуализация элементов, то есть рендер только видимой части списка, что значительно повышает производительность и уменьшает нагрузку на DOM.

Компонент подходит для отображения больших массивов данных, таблиц, списков с карточками и любых элементов, где количество элементов может быть сотни или тысячи. В отличие от стандартного v-for, QVirtualScroll создаёт только те DOM-элементы, которые находятся в зоне видимости, динамически подгружая новые по мере прокрутки.


Основные свойства QVirtualScroll

  • items (Array) — массив объектов для отображения. QVirtualScroll рендерит элементы из этого массива.
  • scroll-target (String | Element) — определяет контейнер, за которым осуществляется прокрутка. Может быть window или конкретный элемент.
  • item-size (Number) — фиксированная высота одного элемента списка. При динамической высоте элементов используются другие методы вычисления.
  • virtual-scroll-target (String | Element) — альтернативное свойство для привязки к конкретному скролл-контейнеру.
  • buffer (Number) — количество элементов до и после видимой области, которые рендерятся для плавной прокрутки.

Пример базового использования:

<q-virtual-scroll
  :items="users"
  item-size="50"
  style="height: 400px"
>
  <template v-slot="{ item }">
    <div class="q-pa-sm">
      {{ item.name }}
    </div>
  </template>
</q-virtual-scroll>

В этом примере каждый элемент списка занимает 50px, а контейнер имеет высоту 400px, что позволяет отображать одновременно около 8 элементов, независимо от общей длины массива users.


Настройка рендеринга элементов

QVirtualScroll предоставляет возможность кастомного рендеринга через слот. В слоте передается объект с ключевыми свойствами:

  • item — текущий элемент массива items.
  • index — индекс текущего элемента.
  • active — булевое значение, показывающее, находится ли элемент в видимой зоне.

Это позволяет создавать сложные карточки, таблицы или интерактивные элементы, не теряя производительности.

<q-virtual-scroll :items="products" item-size="80">
  <template v-slot="{ item, index, active }">
    <q-card v-if="active" class="my-card q-ma-xs">
      <q-card-section>
        <div class="text-h6">{{ item.title }}</div>
        <div>{{ item.description }}</div>
      </q-card-section>
    </q-card>
  </template>
</q-virtual-scroll>

Использование проверки v-if="active" дополнительно снижает количество рендеров, исключая элементы, которые находятся вне зоны видимости.


Горизонтальная и вертикальная прокрутка

По умолчанию QVirtualScroll ориентирован на вертикальную прокрутку, но его можно настроить и для горизонтальной. Для этого необходимо установить CSS свойство white-space: nowrap и задать фиксированную ширину элементов через item-size.

<q-virtual-scroll
  :items="images"
  horizontal
  item-size="150"
  style="width: 600px; overflow-x: auto"
>
  <template v-slot="{ item }">
    <img :src="item.src" class="q-mr-sm" style="width: 150px; height: 150px;" />
  </template>
</q-virtual-scroll>

Динамическая высота элементов

Если элементы имеют разную высоту, можно использовать слот @scroll и метод update() для перерасчета размеров. Также можно применить функцию key-field для точной идентификации элементов.

<q-virtual-scroll
  :items="posts"
  :key-field="'id'"
  :item-size="estimateHeight"
>
  <template v-slot="{ item }">
    <div :style="{ height: item.height + 'px' }">
      {{ item.title }}
    </div>
  </template>
</q-virtual-scroll>

Здесь estimateHeight — средняя оценочная высота элемента. Это позволяет корректно отображать элементы с разной высотой, не нарушая виртуализацию.


Работа с событиями

QVirtualScroll поддерживает несколько событий для управления прокруткой и рендерингом:

  • @scroll — вызывается при прокрутке списка, возвращает объект с текущей позицией и индексом верхнего элемента.
  • @virtual-scroll-update — уведомляет об обновлении виртуализированного контента, полезно для динамических данных.
  • @start и @end — определяют, когда прокрутка дошла до начала или конца списка.

Пример использования:

<q-virtual-scroll
  :items="logs"
  item-size="40"
  @scroll="onScroll"
  @virtual-scroll-update="onUpdate"
>
  <template v-slot="{ item }">
    <div>{{ item.message }}</div>
  </template>
</q-virtual-scroll>

<script>
export default {
  methods: {
    onScroll(evt) {
      console.log('Scroll position:', evt.scrollTop);
    },
    onUpdate(evt) {
      console.log('Visible items:', evt.startIndex, evt.endIndex);
    }
  }
}
</script>

Интеграция с Vuex и асинхронными данными

QVirtualScroll отлично подходит для работы с асинхронными источниками данных. Можно загружать данные порциями, динамически обновлять массив items и автоматически перерасчитывать видимые элементы.

<q-virtual-scroll
  :items="messages"
  item-size="60"
  @scroll="loadMore"
>
  <template v-slot="{ item }">
    <div>{{ item.text }}</div>
  </template>
</q-virtual-scroll>

<script>
export default {
  data() {
    return { messages: [] };
  },
  methods: {
    async loadMore({ endIndex }) {
      if (endIndex >= this.messages.length - 1) {
        const newMessages = await fetchMoreMessages();
        this.messages.push(...newMessages);
      }
    }
  }
}
</script>

Оптимизация производительности

  • Использовать фиксированную высоту элементов, когда это возможно.
  • Ограничивать буфер для элементов вне видимой зоны (buffer).
  • Применять v-if=“active” внутри слота для минимизации рендеринга.
  • Использовать key-field для динамических списков, чтобы избежать лишнего перерасчета.
  • Подключать виртуальный скролл к ограниченному контейнеру, а не к window, если требуется контроль над областью видимости.

QVirtualScroll в Quasar позволяет создавать массивные, высокопроизводительные списки с минимальной нагрузкой на DOM и гибкой кастомизацией визуальных элементов.