Индикаторы загрузки

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

Индикаторы загрузки помогают избежать пустого состояния страницы и создают ощущение отзывчивости интерфейса. В контексте Muuri их использование имеет несколько ключевых особенностей.


Создание базового индикатора загрузки

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

<div id="loading">Загрузка...</div>
<div id="grid" class="grid">
  <div class="item">Элемент 1</div>
  <div class="item">Элемент 2</div>
  <div class="item">Элемент 3</div>
</div>
#loading {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 1.5rem;
  font-weight: bold;
}

.grid {
  visibility: hidden;
}
const grid = new Muuri('.grid', {
  layoutOnInit: false
});

// После полной загрузки всех элементов
window.addEventListener('load', () => {
  document.getElementById('loading').style.display = 'none';
  document.querySelector('.grid').style.visibility = 'visible';
  grid.layout(true);
});

Ключевые моменты:

  • layoutOnInit: false предотвращает преждевременное выравнивание элементов до полной загрузки контента.
  • Скрытие контейнера сетки (visibility: hidden) предотвращает мерцание при загрузке элементов.
  • Индикатор можно стилизовать произвольно, использовать анимацию или спиннер.

Использование событий Muuri для асинхронной загрузки

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

const grid = new Muuri('.grid');

grid.on('layoutEnd', () => {
  document.getElementById('loading').style.display = 'none';
  document.querySelector('.grid').style.visibility = 'visible';
});

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

async function loadItems() {
  const response = await fetch('/api/items');
  const items = await response.json();

  const elements = items.map(item => {
    const el = document.createElement('div');
    el.classList.add('item');
    el.textContent = item.name;
    return el;
  });

  document.querySelector('.grid').append(...elements);
  grid.add(elements);
  grid.layout(true);
}

loadItems();

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


Анимация индикатора загрузки

Для более профессионального эффекта часто используют CSS-анимацию спиннера. Пример:

#loading::after {
  content: '';
  display: block;
  width: 40px;
  height: 40px;
  border: 5px solid #ccc;
  border-top-color: #333;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 10px auto 0 auto;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

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


Динамическое управление индикатором при фильтрации и сортировке

Muuri позволяет динамически фильтровать и сортировать элементы. В таких случаях индикатор можно использовать для отображения временного состояния перерасчета сетки.

function filterGrid(filterFunc) {
  document.getElementById('loading').style.display = 'block';
  grid.filter(filterFunc);
  grid.on('layoutEnd', () => {
    document.getElementById('loading').style.display = 'none';
  });
}

Рекомендации:

  • Использовать индикатор только при длительных операциях, чтобы не раздражать пользователя.
  • Событие layoutEnd — надежный момент для скрытия индикатора после завершения анимаций и выравнивания элементов.
  • Для массового добавления элементов или работы с большим количеством данных можно добавить небольшой таймер, чтобы избежать кратковременного мигания спиннера.

Интеграция с асинхронными библиотеками изображений

Если сетка содержит изображения, индикатор должен ждать полной загрузки картинок. В противном случае элементы могут “прыгать” при появлении.

const images = document.querySelectorAll('.grid img');
let loadedCount = 0;

images.forEach(img => {
  img.onl oad = img.oner ror = () => {
    loadedCount++;
    if (loadedCount === images.length) {
      document.getElementById('loading').style.display = 'none';
      document.querySelector('.grid').style.visibility = 'visible';
      grid.layout(true);
    }
  };
});

Использование события onload и onerror гарантирует, что индикатор исчезнет только после завершения загрузки всех медиафайлов.


Оптимизация UX при больших данных

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

let loadedCount = 0;
const total = items.length;

items.forEach(item => {
  const el = document.createElement('div');
  el.classList.add('item');
  el.textContent = item.name;
  document.querySelector('.grid').append(el);
  
  loadedCount++;
  document.getElementById('loading').textContent = `Загрузка ${Math.round(loadedCount / total * 100)}%`;
});

grid.add(document.querySelectorAll('.item'));
grid.layout(true);
document.getElementById('loading').style.display = 'none';

Такой подход делает ожидание более прозрачным и снижает ощущение “замороженного” интерфейса.


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