Виртуализация списков — техника оптимизации рендеринга больших массивов данных в веб-приложениях. В традиционном подходе каждый элемент массива создаёт соответствующий DOM-узел. При увеличении объёма данных это приводит к значительной нагрузке на браузер и падению производительности. Slim.js предоставляет встроенные возможности для эффективной работы с большими списками через виртуальные контейнеры.
Slim.js работает с DOM через реактивные компоненты, где каждый компонент отслеживает изменения состояния и обновляет только необходимые элементы. Виртуализация строится на принципе динамического создания и удаления DOM-элементов, которые находятся в зоне видимости пользователя. Элементы за пределами экрана не рендерятся, но их данные сохраняются в памяти.
Ключевые моменты:
Для реализации виртуального списка в Slim.js используется директива
each совместно с вычисляемым свойством, которое
ограничивает массив элементов текущей областью видимости.
Пример структуры компонента:
class VirtualList extends Slim {
static get observedAttributes() { return ['items']; }
onBeforeCreated() {
this.state = {
scrollTop: 0,
itemHeight: 40,
viewportHeight: 400,
items: []
};
}
onCreated() {
this.addEventListener('scroll', e => {
this.state.scrollTop = e.target.scrollTop;
this.update();
});
}
get visibleItems() {
const startIndex = Math.floor(this.state.scrollTop / this.state.itemHeight);
const visibleCount = Math.ceil(this.state.viewportHeight / this.state.itemHeight) + 2; // buffer
return this.state.items.slice(startIndex, startIndex + visibleCount)
.map((item, idx) => ({ ...item, _virtualIndex: startIndex + idx }));
}
get template() {
return `
<div style="height:${this.state.items.length * this.state.itemHeight}px; overflow:auto;" class="virtual-container">
<div style="position:relative; height:100%;">
${this.visibleItems.map(item => `
<div style="position:absolute; top:${item._virtualIndex * this.state.itemHeight}px; height:${this.state.itemHeight}px;">
${item.name}
</div>
`).join('')}
</div>
</div>
`;
}
}
Slim.define(VirtualList);
Пояснение:
scrollTop отслеживает текущую прокрутку
контейнера.itemHeight фиксирует высоту каждого элемента
списка.visibleItems вычисляет только те элементы, которые
попадают в область видимости.Фиксированная высота элементов Использование фиксированной высоты ускоряет вычисление видимых элементов, так как не требуется измерять каждый элемент в DOM.
Буферизация Добавление нескольких элементов за пределами видимой области предотвращает «мерцание» при быстрой прокрутке.
Рециклинг узлов При смене видимой области
элементы переиспользуются, вместо того чтобы полностью удалять и
создавать новые DOM-узлы. В Slim.js это можно реализовать через метод
update без пересоздания компонента.
Отложенная загрузка данных Если список содержит тысячи элементов, стоит использовать стратегию lazy loading и подгружать данные частями по мере прокрутки.
Виртуальный список легко комбинируется с асинхронными источниками
данных, например, API. Важно обновлять массив items и
вызывать update(), чтобы пересчитать видимые элементы:
async fetchItems(offset, limit) {
const response = await fetch(`/api/items?offset=${offset}&limit=${limit}`);
const data = await response.json();
this.state.items.push(...data);
this.update();
}
При динамическом обновлении важно корректно управлять индексами виртуальных элементов и сохранять плавность прокрутки.
Виртуализированные элементы могут содержать интерактивные элементы — кнопки, поля ввода, чекбоксы. Основное ограничение: state компонентов должен быть независим от DOM-элемента, иначе при рециклинге состояние может теряться. В Slim.js это решается использованием реактивных свойств, которые хранят данные отдельно от DOM:
<div style="position:absolute; top:${item._virtualIndex * this.state.itemHeight}px;">
<input type="checkbox" checked="${item.checked}" @change="${e => item.checked = e.target.checked}">
${item.name}
</div>
Состояние item.checked хранится в объекте данных,
поэтому при переработке DOM чекбокс сохраняет корректное состояние.
Систематическое применение этих подходов делает Slim.js мощным инструментом для создания высокопроизводительных списков в современных веб-приложениях.