Магазин с фильтрами товаров

Для начала работы с библиотекой Isotope необходимо подключить её к проекту. Обычно используют CDN или локальную версию скрипта:

<link rel="stylesheet" href="styles.css">
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>

После подключения скрипта создаётся контейнер, который будет содержать элементы для фильтрации и сортировки. Структура HTML может выглядеть следующим образом:

<div class="grid">
  <div class="grid-item category-1" data-price="100">Товар 1</div>
  <div class="grid-item category-2" data-price="200">Товар 2</div>
  <div class="grid-item category-1" data-price="150">Товар 3</div>
  <div class="grid-item category-3" data-price="300">Товар 4</div>
</div>

Инициализация Isotope выполняется через Jav * aScript:

var grid = new Isotope('.grid', {
  itemSelector: '.grid-item',
  layoutMode: 'fitRows',
  getSortData: {
    price: '[data-price] parseInt',
    category: '[class*="category-"]'
  }
});

Фильтрация товаров

Фильтрация позволяет скрывать и отображать элементы на основе определённых критериев. Классический пример — фильтрация по категориям товаров:

var filtersElem = document.querySelector('.filters-button-group');
filtersElem.addEventListener('click', function(event) {
  if (!matchesSelector(event.target, 'button')) {
    return;
  }
  var filterValue = event.target.getAttribute('data-filter');
  grid.arrange({ filter: filterValue });
});

HTML для кнопок фильтров:

<div class="filters-button-group">
  <button data-filter="*">Все</button>
  <button data-filter=".category-1">Категория 1</button>
  <button data-filter=".category-2">Категория 2</button>
  <button data-filter=".category-3">Категория 3</button>
</div>

При нажатии на кнопку Isotope автоматически скрывает элементы, не соответствующие выбранной категории, а оставшиеся упорядочивает согласно выбранному макету.

Сортировка товаров

Isotope поддерживает сортировку элементов по различным критериям, например, по цене или алфавиту. Для этого используются атрибуты data-* и функция getSortData:

var sortByGroup = document.querySelector('.sort-by-button-group');
sortByGroup.addEventListener('click', function(event) {
  if (!matchesSelector(event.target, 'button')) {
    return;
  }
  var sortValue = event.target.getAttribute('data-sort-by');
  grid.arrange({ sortBy: sortValue });
});

HTML кнопок сортировки:

<div class="sort-by-button-group">
  <button data-sort-by="original-order">По умолчанию</button>
  <button data-sort-by="price">По цене</button>
  <button data-sort-by="category">По категории</button>
</div>

Можно комбинировать фильтрацию и сортировку: сначала скрываются элементы, не соответствующие фильтру, а затем оставшиеся сортируются.

Анимации и плавные переходы

Isotope автоматически применяет CSS-анимации при изменении положения элементов. Для более плавных переходов можно использовать собственные CSS-переходы:

.grid-item {
  transition: transform 0.4s, opacity 0.4s;
}

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

Множественные фильтры и комбинированные условия

Иногда требуется фильтровать товары по нескольким критериям одновременно, например, по категории и диапазону цены. Для этого создаётся функция-фильтр:

var filters = {};

function filterItems() {
  var filterValue = function(itemElem) {
    var isCategoryMatch = filters.category ? itemElem.classList.contains(filters.category) : true;
    var isPriceMatch = filters.price ? parseInt(itemElem.getAttribute('data-price')) <= filters.price : true;
    return isCategoryMatch && isPriceMatch;
  };
  grid.arrange({ filter: filterValue });
}

document.querySelectorAll('.category-filter button').forEach(function(btn) {
  btn.addEventListener('click', function() {
    filters.category = btn.getAttribute('data-filter').substring(1);
    filterItems();
  });
});

document.querySelectorAll('.price-filter button').forEach(function(btn) {
  btn.addEventListener('click', function() {
    filters.price = parseInt(btn.getAttribute('data-max-price'));
    filterItems();
  });
});

HTML кнопок для диапазона цены:

<div class="price-filter">
  <button data-max-price="150">До 150</button>
  <button data-max-price="250">До 250</button>
  <button data-max-price="500">До 500</button>
</div>

Такая структура позволяет создавать динамическое сочетание фильтров, где одновременно учитываются разные критерии.

Респонсивность и перестройка макета

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

window.addEventListener('resize', function() {
  grid.layout();
});

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

Lazy Loading и динамическое добавление элементов

Isotope поддерживает динамическое добавление элементов через метод appended:

var newItems = document.querySelectorAll('.new-grid-item');
grid.appended(newItems);
grid.layout();

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

Работа с изображениями

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

imagesLoaded('.grid', function() {
  grid.layout();
});

Библиотека imagesLoaded корректно учитывает размеры изображений и предотвращает «скачущие» элементы на странице.

Настройка макета и стилевых эффектов

Isotope поддерживает несколько режимов раскладки (masonry, fitRows, vertical, cellsByRow). Для магазина товаров чаще используют fitRows или masonry:

var grid = new Isotope('.grid', {
  itemSelector: '.grid-item',
  layoutMode: 'masonry',
  masonry: {
    gutter: 20
  }
});

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

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

При больших объёмах товаров важно учитывать:

  • Минимизировать количество DOM-элементов, подлежащих фильтрации одновременно.
  • Использовать requestAnimationFrame при сложных анимациях.
  • Загружать изображения асинхронно и инициализировать Isotope после их полной загрузки.
  • Компактно использовать функции фильтрации и сортировки для предотвращения лишних вычислений.

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