Библиотека Packery предназначена для построения адаптивных сеток с произвольным расположением элементов. В реальных интерфейсах сетка редко остается статичной: карточки добавляются, удаляются, изменяют размеры, загружаются по сети или формируются на основе пользовательских действий. Поддержка динамического контента — один из ключевых аспектов работы Packery.
Механизм перерасчёта макета основан на повторной компоновке элементов внутри контейнера. Packery отслеживает размеры элементов и их доступное пространство, размещая блоки по принципу «упаковки» (bin-packing).
Типичная инициализация:
var grid = document.querySelector('.grid');
var pckry = new Packery(grid, {
itemSelector: '.grid-item',
gutter: 10
});
Контейнер .grid управляет позиционированием всех
элементов .grid-item. После инициализации сетка может
изменяться программно.
appendedДобавление новых блоков — наиболее распространённая операция при работе с динамическим интерфейсом. Например, элементы могут загружаться с сервера, появляться после фильтрации или генерироваться скриптом.
Packery предоставляет метод appended, который корректно
интегрирует новые элементы в существующий макет.
var newItems = document.createElement('div');
newItems.classList.add('grid-item');
grid.appendChild(newItems);
pckry.appended(newItems);
Алгоритм работы метода:
Добавление нескольких элементов выполняется через массив или NodeList:
var items = [];
for (var i = 0; i < 5; i++) {
var item = document.createElement('div');
item.className = 'grid-item';
grid.appendChild(item);
items.push(item);
}
pckry.appended(items);
Это значительно эффективнее последовательного добавления элементов.
Удаление элементов также должно происходить через API Packery, иначе внутреннее состояние сетки нарушается.
Используется метод remove.
var item = grid.querySelector('.grid-item');
pckry.remove(item);
pckry.layout();
Процесс удаления включает:
Для удаления нескольких элементов:
var items = grid.querySelectorAll('.grid-item.to-delete');
pckry.remove(items);
pckry.layout();
После удаления Packery автоматически перераспределяет оставшиеся элементы.
При динамических изменениях размеров или структуры необходимо вручную инициировать перерасчёт макета.
Метод layout запускает алгоритм
перепозиционирования.
pckry.layout();
Перерасчёт требуется в следующих ситуациях:
Packery поддерживает плавное появление элементов. Для этого используется CSS-анимация и правильная последовательность действий.
var item = document.createElement('div');
item.className = 'grid-item hidden';
grid.appendChild(item);
pckry.appended(item);
setTimeout(function() {
item.classList.remove('hidden');
}, 50);
CSS:
.grid-item {
transition: transform 0.4s, opacity 0.4s;
}
.hidden {
opacity: 0;
}
Такой подход позволяет добиться мягкой интеграции новых элементов в сетку.
Одной из наиболее распространённых проблем динамических сеток является загрузка изображений. Пока изображение не загрузилось, браузер не знает окончательного размера элемента.
Это может привести к неправильному расположению элементов.
Для решения используется библиотека imagesLoaded.
imagesLoaded(grid, function() {
pckry.layout();
});
При добавлении новых элементов:
var items = document.querySelectorAll('.grid-item');
imagesLoaded(items, function() {
pckry.appended(items);
});
Таким образом Packery выполняет перерасчёт только после получения точных размеров.
Если размеры элемента изменяются динамически (например, раскрытие карточки), необходимо уведомить Packery.
Используется метод reloadItems или
layout.
pckry.layout();
Если изменения затрагивают структуру элементов:
pckry.reloadItems();
pckry.layout();
reloadItems пересканирует контейнер и заново
зарегистрирует элементы.
Часто элементы подгружаются с сервера. Алгоритм работы с Packery следующий:
Пример:
fetch('/api/items')
.then(response => response.text())
.then(html => {
var temp = document.createElement('div');
temp.innerHTML = html;
var items = temp.querySelectorAll('.grid-item');
items.forEach(function(item){
grid.appendChild(item);
});
pckry.appended(items);
});
Такой подход используется при реализации infinite scroll.
Infinite Scroll позволяет подгружать новые элементы по мере прокрутки страницы.
Основная логика:
window.addEventListener('scroll', function(){
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) {
loadMore();
}
});
Функция загрузки:
function loadMore(){
fetch('/items')
.then(res => res.text())
.then(html => {
var temp = document.createElement('div');
temp.innerHTML = html;
var items = temp.querySelectorAll('.grid-item');
items.forEach(function(item){
grid.appendChild(item);
});
pckry.appended(items);
});
}
После добавления новых карточек Packery автоматически перераспределяет пространство.
Адаптивные интерфейсы требуют пересчёта сетки при изменении размеров окна.
window.addEventListener('resize', function() {
pckry.layout();
});
Однако частые вызовы могут снижать производительность. Используется debounce.
function debounce(fn, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(fn, delay);
};
}
window.addEventListener('resize', debounce(function(){
pckry.layout();
}, 200));
Это уменьшает количество перерасчётов.
Packery часто используется вместе с Draggabilly для перетаскивания элементов.
После перемещения элементов сетка должна обновляться.
var draggie = new Draggabilly(item);
pckry.bindDraggabillyEvents(draggie);
При добавлении новых элементов необходимо привязывать drag-обработчики:
items.forEach(function(item) {
var draggie = new Draggabilly(item);
pckry.bindDraggabillyEvents(draggie);
});
Это обеспечивает корректную работу динамически добавленных карточек.
При работе с большим количеством динамических элементов следует учитывать несколько факторов.
Добавление элементов группами:
pckry.appended(items);
вместо последовательных вызовов.
Необходимо избегать частых вызовов layout.
Лучше объединять изменения:
pckry.reloadItems();
pckry.layout();
requestAnimationFrameДля плавного обновления интерфейса:
requestAnimationFrame(function(){
pckry.layout();
});
HTML:
<div class="grid">
<div class="grid-item"></div>
<div class="grid-item"></div>
</div>
<button id="add">Добавить</button>
Jav * aScript:
var grid = document.querySelector('.grid');
var pckry = new Packery(grid, {
itemSelector: '.grid-item',
gutter: 10
});
document.getElementById('add').addEventListener('click', function(){
var item = document.createElement('div');
item.className = 'grid-item';
grid.appendChild(item);
pckry.appended(item);
});
CSS:
.grid {
position: relative;
}
.grid-item {
width: 200px;
height: 150px;
background: #ccc;
margin-bottom: 10px;
}
Сетка автоматически перестраивается при добавлении новых элементов, обеспечивая плотную упаковку и эффективное использование пространства.