Обновление после изменений DOM

Библиотека Muuri предоставляет мощные инструменты для построения динамических сеток с возможностью перетаскивания элементов и анимаций. Одной из ключевых особенностей является способность корректно реагировать на изменения в DOM, будь то добавление, удаление или изменение размеров элементов. Правильное управление обновлением сетки после таких изменений обеспечивает стабильность и плавность интерфейса.


Основные методы обновления сетки

Muuri использует несколько методов для синхронизации состояния сетки с реальным DOM:

  1. refreshItems() Метод обновляет внутреннее представление элементов сетки. Его стоит вызывать после того, как элементы были добавлены, удалены или их размеры изменились. Пример использования:

    const grid = new Muuri('.grid');
    
    // Добавление нового элемента в DOM
    const newItem = document.createElement('div');
    newItem.classList.add('item');
    grid.getElement().appendChild(newItem);
    
    // Обновление сетки
    grid.refreshItems().layout();

    Здесь refreshItems() сканирует DOM и добавляет новые элементы в внутреннюю структуру Muuri, а layout() пересчитывает расположение всех элементов.

  2. add() и remove() Эти методы позволяют более явно управлять элементами сетки:

    const newItem = document.createElement('div');
    newItem.classList.add('item');
    grid.add(newItem); // автоматически обновляет внутреннюю структуру и выполняет анимацию

    Удаление элемента:

    const itemToRemove = grid.getItems()[0];
    grid.remove(itemToRemove, { removeElements: true });

    Параметр removeElements: true гарантирует удаление элемента из DOM одновременно с его удалением из сетки.

  3. layout() Метод отвечает исключительно за перераспределение элементов. Вызывать его следует после любых изменений, влияющих на размеры или порядок элементов.

    grid.layout(true); // true означает принудительное перераспределение всех элементов

Автоматическое обновление при изменении размеров

Muuri может автоматически отслеживать изменения размеров элементов с помощью dragRelease и resize событий. Однако в случаях динамического изменения контента (например, загрузка изображений или изменение текста) рекомендуется использовать refreshItems() с последующим layout().

Пример с изображениями:

const images = grid.getItems().map(item => item.getElement().querySelector('img'));

images.forEach(img => {
  img.onl oad = () => {
    grid.refreshItems([img.parentElement]).layout();
  };
});

Здесь refreshItems([element]) обновляет только конкретный элемент, что экономит ресурсы при больших сетках.


Управление динамическим добавлением и удалением элементов

Muuri предоставляет возможность управлять сеткой при частых изменениях DOM без полной пересборки:

  • Добавление множества элементов:
const items = [];
for (let i = 0; i < 10; i++) {
  const el = document.createElement('div');
  el.classList.add('item');
  el.textContent = `Элемент ${i}`;
  items.push(el);
}
grid.add(items);
  • Удаление элементов по условию:
const itemsToRemove = grid.getItems().filter(item => item.getElement().textContent.includes('Удалить'));
grid.remove(itemsToRemove, { removeElements: true });

Использование массивов ускоряет процесс и минимизирует количество анимаций при массовых изменениях.


Интеграция с MutationObserver

Для сложных интерфейсов, где DOM изменяется динамически, эффективным решением является MutationObserver:

const observer = new MutationObserver(mutations => {
  let needsRefresh = false;

  mutations.forEach(mutation => {
    if (mutation.addedNodes.length || mutation.removedNodes.length) {
      needsRefresh = true;
    }
  });

  if (needsRefresh) {
    grid.refreshItems().layout();
  }
});

observer.observe(grid.getElement(), { childList: true, subtree: true });

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


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

  • Обновлять только изменённые элементы: refreshItems([element1, element2]) вместо refreshItems() для всей сетки.
  • Использовать батчи: Собирать несколько изменений DOM и обновлять сетку разом.
  • Минимизировать вызовы layout(): Не вызывать layout() после каждого отдельного изменения, а комбинировать с refreshItems().

Особенности работы с асинхронным контентом

При работе с контентом, загружаемым асинхронно (например, с API), важно обновлять сетку после полной загрузки элементов:

fetch('/api/items')
  .then(res => res.json())
  .then(data => {
    const elements = data.map(item => {
      const el = document.createElement('div');
      el.classList.add('item');
      el.textContent = item.name;
      return el;
    });
    grid.add(elements);
  });

Здесь grid.add(elements) автоматически интегрирует новые элементы в сетку и запускает анимацию их появления.


Ключевые рекомендации

  • Использовать refreshItems() после любых изменений DOM, влияющих на элементы сетки.
  • Вызов layout() обязателен для перерасчета положения элементов.
  • Применять MutationObserver для автоматического отслеживания изменений при сложных динамических интерфейсах.
  • Оптимизировать производительность через выборочное обновление элементов и объединение изменений.

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