Синхронизация нескольких экземпляров

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

Ключевой момент синхронизации заключается в том, что Packery не предоставляет встроенного механизма для автоматической синхронизации нескольких контейнеров, поэтому требуется использование программных паттернов на стороне Jav * aScript: событий и ручного управления элементами.


Создание нескольких экземпляров

Для начала создаются два или более экземпляров:

var grid1 = new Packery('.grid1', {
  itemSelector: '.grid-item',
  gutter: 10,
});

var grid2 = new Packery('.grid2', {
  itemSelector: '.grid-item',
  gutter: 10,
});

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


Использование событий Packery

Packery генерирует несколько полезных событий:

  • layoutComplete — вызывается после завершения перестановки элементов.
  • dragItemPositioned — срабатывает при перемещении элемента через Draggabilly.
  • removeComplete — после удаления элемента из контейнера.
  • fitComplete — после того как элемент был «втиснут» в сетку.

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

grid1.on('layoutComplete', function() {
  grid2.layout(); // Перестроение второго контейнера после изменений в первом
});

grid2.on('dragItemPositioned', function() {
  grid1.layout(); // Обновление первого контейнера при перетаскивании элементов во втором
});

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


Синхронизация элементов между контейнерами

Иногда требуется не только перестраивать макет, но и переносить элементы между контейнерами. Packery предоставляет методы для добавления и удаления элементов динамически:

// Удаление элемента из grid1
grid1.remove(itemElement);
grid1.layout();

// Добавление элемента в grid2
grid2.appended(itemElement);
grid2.layout();

Важно помнить:

  • После remove() элемент должен быть удалён из DOM или готов к перемещению.
  • appended() добавляет элемент в DOM контейнера и включает его в раскладку.

Такой подход позволяет перемещать элементы между сетками в реальном времени, сохраняя корректное выравнивание и анимацию.


Совместная работа с Draggabilly

Packery тесно интегрируется с библиотекой Draggabilly для перетаскивания элементов. Для синхронизации нескольких контейнеров при использовании Draggabilly необходимо:

  1. Создать Draggabilly-инстанс для каждого элемента.
  2. Привязать его к Packery через метод bindDraggabillyEvents.
  3. В обработчике события dragItemPositioned вызывать перестройку других экземпляров.

Пример:

var draggies1 = [];
grid1.getItemElements().forEach(function(itemElem) {
  var draggie = new Draggabilly(itemElem);
  grid1.bindDraggabillyEvents(draggie);
  draggies1.push(draggie);
});

grid1.on('dragItemPositioned', function() {
  grid2.layout();
});

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


Синхронизация размеров контейнеров

Если высота или ширина контейнера зависит от содержимого, необходимо обновлять размеры всех синхронизированных контейнеров при изменении любого из них:

function syncContainerSizes() {
  var maxHeight = Math.max(grid1.element.offsetHeight, grid2.element.offsetHeight);
  grid1.element.style.height = maxHeight + 'px';
  grid2.element.style.height = maxHeight + 'px';
}

grid1.on('layoutComplete', syncContainerSizes);
grid2.on('layoutComplete', syncContainerSizes);

Это предотвращает разрыв макета и обеспечивает согласованное визуальное восприятие.


Оптимизация синхронизации

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

  • Использовать requestAnimationFrame для минимизации количества перестроек.
  • Ограничивать вызовы layout() только при действительно изменившихся элементах.
  • При переносе элементов между контейнерами применять remove() и appended() пакетно, а не по одному, чтобы сократить количество перерасчётов.

Пример с оптимизацией:

var needsLayout = false;

function scheduleLayout() {
  if (!needsLayout) {
    needsLayout = true;
    requestAnimationFrame(function() {
      grid1.layout();
      grid2.layout();
      needsLayout = false;
    });
  }
}

grid1.on('dragItemPositioned', scheduleLayout);
grid2.on('dragItemPositioned', scheduleLayout);

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


Итоговая структура синхронизации

Основные принципы синхронизации нескольких экземпляров Packery:

  1. Создавать отдельные экземпляры для каждого контейнера.
  2. Использовать события Packery (layoutComplete, dragItemPositioned) для уведомления других экземпляров.
  3. Для переноса элементов применять remove() и appended().
  4. Обновлять размеры контейнеров для согласованного макета.
  5. Оптимизировать вызовы layout() через пакетную обработку или requestAnimationFrame.

Соблюдение этих правил позволяет строить сложные, взаимозависимые сетки, сохраняя анимацию и стабильность макета на странице.