Masonry — это мощная библиотека для организации сетки элементов с динамическими размерами. Одной из ключевых возможностей является одновременная работа сортировки и фильтрации элементов. В стандартном применении Masonry управляет положением элементов на основе их размеров и порядка в DOM, но при добавлении логики сортировки и фильтров требуется дополнительная работа с данными элементов и обновление сетки после изменений.
Для корректной работы необходимо подготовить каждый элемент сетки. Обычно элементы имеют классы для фильтрации и атрибуты для сортировки. Например:
<div class="grid">
<div class="grid-item" data-category="nature" data-price="20">Элемент 1</div>
<div class="grid-item" data-category="architecture" data-price="50">Элемент 2</div>
<div class="grid-item" data-category="nature" data-price="30">Элемент 3</div>
</div>
data-category — используется для фильтрации по
категориям.data-price — пример атрибута для сортировки по
числовому значению.Важно, чтобы все элементы имели однородную структуру атрибутов, иначе сортировка и фильтрация могут работать некорректно.
Для начала необходимо создать экземпляр Masonry и подключить элементы сетки:
const grid = document.querySelector('.grid');
const msnry = new Masonry(grid, {
itemSelector: '.grid-item',
columnWidth: '.grid-item',
percentPosition: true,
gutter: 10
});
itemSelector определяет, какие элементы будут
участвовать в сетке.columnWidth может быть фиксированным или привязанным к
ширине элемента.percentPosition: true позволяет сетке быть
отзывчивой.Фильтрация подразумевает отображение только тех элементов, которые соответствуют критериям. Простейший способ — управление видимостью через CSS:
function filterItems(category) {
const items = grid.querySelectorAll('.grid-item');
items.forEach(item => {
if (category === 'all' || item.dataset.category === category) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
msnry.layout();
}
display: none исключает элемент из сетки, но Masonry
после вызова layout() корректно перераспределяет оставшиеся
элементы.'all' позволяет отображать все элементы.Для сортировки удобно использовать массив элементов
и функцию sort():
function sortItems(attribute, ascending = true) {
const items = Array.from(grid.querySelectorAll('.grid-item'));
items.sort((a, b) => {
const aVal = parseFloat(a.dataset[attribute]);
const bVal = parseFloat(b.dataset[attribute]);
return ascending ? aVal - bVal : bVal - aVal;
});
items.forEach(item => grid.appendChild(item));
msnry.reloadItems();
msnry.layout();
}
grid.appendChild(item) перемещает элемент в DOM,
Masonry обновляет позиции.reloadItems() сообщает Masonry, что порядок элементов
изменился.layout() перераспределяет элементы в новой
последовательности.При одновременном использовании фильтров и сортировки важно сохранять текущее состояние фильтра при изменении порядка элементов:
let currentFilter = 'all';
let currentSort = { attribute: 'price', ascending: true };
function updateGrid() {
const items = Array.from(grid.querySelectorAll('.grid-item'));
// Применяем фильтр
const filteredItems = items.filter(item =>
currentFilter === 'all' || item.dataset.category === currentFilter
);
// Применяем сортировку к фильтрованным элементам
filteredItems.sort((a, b) => {
const aVal = parseFloat(a.dataset[currentSort.attribute]);
const bVal = parseFloat(b.dataset[currentSort.attribute]);
return currentSort.ascending ? aVal - bVal : bVal - aVal;
});
// Скрываем все элементы, затем отображаем отфильтрованные
items.forEach(item => item.style.display = 'none');
filteredItems.forEach(item => {
item.style.display = '';
grid.appendChild(item);
});
msnry.reloadItems();
msnry.layout();
}
updateGrid() объединяет оба действия в
один поток, исключая рассинхронизацию.currentFilter и currentSort позволяют
динамически изменять критерии без пересоздания сетки.При больших сетках рекомендуется:
display: none вместо удаления элементов из
DOM — это быстрее.layout() — лучше вызвать один раз
после фильтрации и сортировки.Masonry хорошо работает с анимациями:
.grid-item {
transition: transform 0.4s, opacity 0.4s;
}
opacity можно использовать при скрытии/отображении
элементов для более мягкой фильтрации.Если новые элементы добавляются после инициализации:
function addNewItem(element) {
grid.appendChild(element);
msnry.appended(element);
updateGrid(); // применяем текущие фильтр и сортировку
}
appended() сообщает Masonry о новых элементах,
чтобы корректно рассчитать позиции.updateGrid() гарантирует, что новые
элементы соответствуют текущим фильтрам и сортировке.updateGrid(), которая учитывает оба
состояния.appended() и повторное применение текущих правил.Такой подход обеспечивает гибкую, отзывчивую и легко расширяемую сетку, где фильтрация и сортировка работают синхронно и плавно.