Интерфейсы современных веб-приложений часто работают с большими массивами данных: списками пользователей, каталогами товаров, логами, сообщениями, результатами поиска и другими коллекциями. В некоторых случаях количество элементов может достигать десятков или сотен тысяч записей.
Если попытаться отобразить такой список напрямую в DOM, создавая отдельный элемент для каждой записи, возникают серьёзные проблемы производительности:
Даже при использовании реактивного фреймворка Vue, который эффективно управляет DOM, проблема большого количества элементов остаётся актуальной. Каждый элемент списка становится полноценным DOM-узлом, участвующим в процессе обновления.
Для решения этой задачи применяется техника виртуализации списков.
Виртуализация списка — это метод отображения только той части элементов, которая в данный момент находится в видимой области интерфейса.
Основная идея заключается в следующем:
Таким образом:
Визуально пользователь видит обычный длинный список, хотя фактически браузер работает лишь с небольшим количеством элементов.
В библиотеке Vuetify виртуализация реализована через компонент
VVirtualScroll. Он предназначен для
отображения длинных списков с минимальной нагрузкой на браузер.
Основные возможности компонента:
Благодаря этому компоненту можно эффективно отображать:
Простейший пример виртуального списка.
<template>
<v-virtual-scroll
:items="items"
height="400"
>
<template v-slot="{ item }">
<v-list-item>
<v-list-item-title>{{ item }}</v-list-item-title>
</v-list-item>
</template>
</v-virtual-scroll>
</template>
<script setup>
const items = Array.from({ length: 10000 }, (_, i) => `Элемент ${i}`)
</script>
Особенности этого примера:
Параметр height задаёт высоту области прокрутки.
Свойство items содержит массив данных, который
используется для генерации списка.
:v-items="items"
Элементы могут быть:
Пример с объектами:
const users = [
{ id: 1, name: 'Иван' },
{ id: 2, name: 'Мария' },
{ id: 3, name: 'Алексей' }
]
Использование в шаблоне:
<template v-slot="{ item }">
<v-list-item>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item>
</template>
Компонент использует scoped slot, позволяющий полностью контролировать внешний вид элементов списка.
Слот получает объект со следующими свойствами:
item — текущий элемент массива;index — индекс элемента;props — вспомогательные свойства.Пример:
<template v-slot="{ item, index }">
<div class="list-item">
{{ index }} — {{ item }}
</div>
</template>
Это позволяет строить любые интерфейсы:
Для корректной работы виртуализации компонент должен знать высоту каждого элемента.
Если элементы имеют одинаковую высоту, используется свойство
item-height.
<v-virtual-scroll
:items="items"
height="400"
item-height="48"
>
Это позволяет компоненту:
Иногда элементы списка имеют различную высоту.
Например:
В таких случаях можно использовать автоматическое определение высоты.
Однако это увеличивает вычислительную нагрузку и может снижать производительность. Поэтому при возможности рекомендуется использовать фиксированную высоту элементов.
Компонент VVirtualScroll поддерживает управление
прокруткой через стандартные свойства контейнера.
Например, можно прокручивать список программно.
const container = ref(null)
container.value.scrollTop = 1000
Это может использоваться для:
Часто виртуализация применяется вместе со списком Vuetify.
Пример:
<v-list height="400">
<v-virtual-scroll
:items="items"
item-height="56"
>
<template v-slot="{ item }">
<v-list-item>
<v-list-item-title>{{ item }}</v-list-item-title>
</v-list-item>
</template>
</v-virtual-scroll>
</v-list>
Такой подход позволяет сохранять внешний вид стандартных компонентов Vuetify.
Виртуализация позволяет эффективно отображать очень большие массивы.
Пример генерации большого списка:
const items = Array.from({ length: 50000 }, (_, i) => ({
id: i,
title: `Запись ${i}`
}))
Даже при 50 000 элементов интерфейс остаётся плавным, поскольку в DOM присутствует лишь небольшая часть элементов.
При работе с виртуальными списками рекомендуется соблюдать несколько правил оптимизации.
Каждый элемент списка должен быть максимально простым:
При работе со списками важно использовать ключи.
<div :key="item.id">
Это позволяет Vue эффективнее управлять обновлениями.
Иногда список содержит не только текст, но и изображения.
В таких случаях рекомендуется:
Виртуализация хорошо сочетается с техникой infinite scroll — бесконечной прокруткой.
Принцип работы:
Пример логики:
function loadMore() {
const newItems = fetchNextItems()
items.value.push(...newItems)
}
Комбинация виртуализации и бесконечной прокрутки позволяет:
В реальных приложениях список обычно формируется на основе данных с сервера.
Типичный сценарий:
v-virtual-scroll.Пример:
const items = ref([])
async function loadUsers() {
const response = await fetch('/api/users')
items.value = await response.json()
}
После загрузки данные автоматически отображаются благодаря реактивности Vue.
Несмотря на высокую эффективность, виртуализация имеет ряд особенностей.
Элементы, находящиеся вне экрана:
querySelector.Это важно учитывать при:
Некоторые сложные элементы могут изменять высоту после рендеринга (например, изображения после загрузки). Это может влиять на точность вычислений.
Виртуализированные списки могут быть менее удобны для индексирования поисковыми системами, поскольку часть элементов отсутствует в DOM.
Виртуализация списков особенно полезна в следующих типах интерфейсов.
Мессенджеры
Административные панели
Каталоги товаров
Аналитические панели
Во всех этих случаях виртуализация позволяет значительно повысить производительность интерфейса.
Обычный список:
Виртуализированный список:
Разница в производительности может быть десятки раз.
Использование виртуальных списков приводит к нескольким архитектурным преимуществам:
Поэтому виртуализация считается одним из ключевых инструментов оптимизации интерфейсов в современных веб-приложениях.