Виртуализация больших списков

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

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

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

  • items — массив данных для рендеринга.
  • virtual-scroll-item-size — фиксированная высота одного элемента списка. Если элементы имеют динамическую высоту, используется другой подход (см. ниже).
  • scroll-target — элемент, к которому привязывается виртуальный скролл. По умолчанию — окно браузера.
  • visible-items-padding — количество элементов до и после видимой зоны, рендерящихся для плавного скролла.

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

<template>
  <q-virtual-scroll
    :items="users"
    :virtual-scroll-item-size="50"
    scroll-target="#scroll-container"
  >
    <template v-slot="{ item }">
      <div class="user-item">{{ item.name }}</div>
    </template>
  </q-virtual-scroll>
</template>

<script>
export default {
  data() {
    return {
      users: Array.from({ length: 10000 }, (_, i) => ({ name: `User ${i + 1}` }))
    };
  }
};
</script>

<style>
.user-item {
  height: 50px;
  display: flex;
  align-items: center;
  padding: 0 10px;
  border-bottom: 1px solid #ccc;
}
#scroll-container {
  height: 500px;
  overflow-y: auto;
}
</style>

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

Для списков, где элементы имеют различную высоту, используется слот virtual-scroll-item-size с функцией, возвращающей размер конкретного элемента:

<q-virtual-scroll
  :items="messages"
  :virtual-scroll-item-size="getItemSize"
>
  <template v-slot="{ item }">
    <div class="message-item">{{ item.text }}</div>
  </template>
</q-virtual-scroll>

<script>
export default {
  data() {
    return {
      messages: [
        { text: 'Short message' },
        { text: 'Long message that may take multiple lines' }
      ]
    };
  },
  methods: {
    getItemSize(item) {
      return item.text.length > 50 ? 100 : 50;
    }
  }
};
</script>

Это позволяет корректно виртуализировать списки с непостоянной высотой элементов без искажений скролла.

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

  • visible-items-padding — рекомендуется задавать 2–5 элементов до и после видимой зоны, чтобы скролл оставался плавным.
  • track-by — использование уникального идентификатора для каждого элемента уменьшает количество перерисовок.
  • memoization — вычисления внутри слота можно оптимизировать с помощью кеширования, если рендер элементов дорогой.
<q-virtual-scroll
  :items="products"
  virtual-scroll-item-size="60"
  track-by="id"
>
  <template v-slot="{ item }">
    <ProductCard :product="item" />
  </template>
</q-virtual-scroll>

Поддержка Infinite Scroll

Компонент QVirtualScroll легко интегрируется с бесконечным скроллом. Для этого используется событие @virtual-scroll:

<q-virtual-scroll
  :items="items"
  :virtual-scroll-item-size="70"
  @virtual-scroll="onScroll"
>
  <template v-slot="{ item }">
    <div>{{ item.name }}</div>
  </template>
</q-virtual-scroll>

<script>
export default {
  data() {
    return {
      items: [],
      page: 0
    };
  },
  methods: {
    onScroll({ to, from, direction }) {
      if (to + 10 >= this.items.length) {
        this.loadMore();
      }
    },
    loadMore() {
      const newItems = Array.from({ length: 50 }, (_, i) => ({ name: `Item ${this.items.length + i + 1}` }));
      this.items = [...this.items, ...newItems];
      this.page++;
    }
  }
};
</script>

Стилизация и адаптивность

  • Каждый элемент списка должен иметь фиксированную высоту (для базовой виртуализации) или корректно рассчитываемую высоту (для динамической).
  • Контейнер скролла обязательно должен иметь ограниченную высоту и overflow-y: auto.
  • Комбинация с Quasar Layout и QPageContainer позволяет создавать адаптивные списки, растягивающиеся на всю доступную площадь экрана.

Применение в реальных проектах

Виртуализация списков особенно актуальна для:

  • Панелей администратора с таблицами тысяч пользователей.
  • Чатов и мессенджеров с историей сообщений.
  • Каталогов товаров с фильтрацией и сортировкой.
  • Логов и аналитических панелей с большим количеством записей.

Правильная настройка QVirtualScroll позволяет экономить память, снижать количество DOM-элементов, ускорять рендеринг и улучшать отзывчивость интерфейса.

Полезные слоты и события

  • v-slot="{ item, index }" — доступ к данным и индексу.
  • @virtual-scroll — отслеживание текущей видимой зоны.
  • scroll-target — возможность привязки к любому контейнеру, не только к окну.

Эта гибкость делает QVirtualScroll универсальным инструментом для работы с большими списками в приложениях на Quasar.