Ленивая загрузка

Packery — это мощная библиотека для построения сеток с динамическим расположением элементов, где важным аспектом является оптимизация загрузки контента. Ленивая загрузка (lazy loading) позволяет загружать элементы или изображения только по мере необходимости, что снижает первоначальное время загрузки страницы и уменьшает нагрузку на браузер.


Основные подходы к ленивой загрузке

  1. Использование события прокрутки (scroll event) Самый простой способ — отслеживать позицию прокрутки и подгружать элементы, когда они появляются в видимой области окна. Для Packery это особенно полезно при добавлении новых плиток динамически:
let container = document.querySelector('.grid');
let pckry = new Packery(container, {
  itemSelector: '.grid-item',
  gutter: 10
});

window.addEventListener('scroll', () => {
  let scrollPosition = window.scrollY + window.innerHeight;
  let lastItem = container.lastElementChild;
  if (lastItem.offsetTop < scrollPosition + 100) {
    loadMoreItems();
  }
});

function loadMoreItems() {
  // AJAX-запрос или генерация новых элементов
  let newItem = document.createElement('div');
  newItem.className = 'grid-item';
  newItem.innerHTML = '<img data-src="image.jpg">';
  container.appendChild(newItem);
  pckry.appended(newItem);
  lazyLoadImage(newItem);
}

Здесь pckry.appended используется для уведомления Packery о добавлении новых элементов, чтобы они корректно распределились по сетке.


  1. Ленивая загрузка изображений через IntersectionObserver Этот подход позволяет отслеживать, когда элемент появляется в области видимости браузера, и подгружать изображение только в этот момент:
function lazyLoadImage(item) {
  let img = item.querySelector('img[data-src]');
  if (!img) return;

  let observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        img.src = img.dataset.src;
        img.removeAttribute('data-src');
        observer.unobserve(entry.target);
      }
    });
  });
  observer.observe(img);
}

После установки изображения Packery необходимо пересчитать расположение:

img.onl oad = () => {
  pckry.layout();
};

Это гарантирует, что сетка будет корректно перестраиваться при загрузке каждого изображения.


Добавление новых элементов динамически

Packery предоставляет методы для динамического обновления сетки:

  • pckry.appended(elements) — уведомляет сетку о новых элементах.
  • pckry.layout() — пересчитывает позиции всех элементов.
  • pckry.reloadItems() — полностью пересчитывает список элементов, если они были добавлены или удалены вне контролируемого процесса.

Пример комбинированного подхода с ленивой загрузкой:

function addItems(itemsData) {
  let items = itemsData.map(data => {
    let div = document.createElement('div');
    div.className = 'grid-item';
    div.innerHTML = `<img data-src="${data.src}">`;
    lazyLoadImage(div);
    return div;
  });

  items.forEach(item => container.appendChild(item));
  pckry.appended(items);
}

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

  • Фрагменты DOM: при добавлении множества элементов лучше использовать DocumentFragment, чтобы снизить количество перерасчетов:
let fragment = document.createDocumentFragment();
items.forEach(item => fragment.appendChild(item));
container.appendChild(fragment);
pckry.appended(items);
  • Отложенная инициализация Packery: инициализация сетки после первой порции загруженных изображений уменьшает визуальные прыжки элементов.

  • Debounce для событий прокрутки: предотвращает частые вызовы функции загрузки:

function debounce(func, wait = 100) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

window.addEventListener('scroll', debounce(() => {
  checkLoadMore();
}));

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

  • Размеры изображений могут быть неизвестны до их загрузки. Для корректного распределения элементов Packery желательно использовать фиксированные размеры контейнеров или предварительное определение размеров через CSS.
  • После загрузки изображения всегда следует вызывать pckry.layout(), иначе сетка может «съехать».

Итоговый паттерн для ленивой загрузки

  1. Инициализация Packery после рендеринга первой порции элементов.
  2. Использование IntersectionObserver для подгрузки изображений.
  3. Динамическое добавление элементов через pckry.appended().
  4. Вызов pckry.layout() после загрузки каждого нового элемента.
  5. Оптимизация событий прокрутки через debounce и DocumentFragment.

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