Фильтрация по атрибутам данных

Muuri — это мощная библиотека для организации динамических сеток с возможностью сортировки, фильтрации и перетаскивания элементов. Одним из ключевых инструментов управления содержимым сетки является фильтрация по атрибутам данных (data-*). Она позволяет гибко управлять отображением элементов без необходимости изменения структуры DOM или применения сложных условий через JavaScript.


Настройка элементов с атрибутами данных

Каждый элемент сетки в Muuri — это HTML-элемент, который может содержать кастомные атрибуты. Для фильтрации удобно использовать data-* атрибуты:

<div class="grid">
  <div class="item" data-category="fruit" data-price="low">
    <div class="item-content">Яблоко</div>
  </div>
  <div class="item" data-category="fruit" data-price="high">
    <div class="item-content">Манго</div>
  </div>
  <div class="item" data-category="vegetable" data-price="low">
    <div class="item-content">Морковь</div>
  </div>
  <div class="item" data-category="vegetable" data-price="high">
    <div class="item-content">Авокадо</div>
  </div>
</div>

В этом примере каждый элемент имеет атрибуты data-category и data-price, которые будут использоваться для фильтрации.


Инициализация сетки Muuri

Для работы с фильтрацией необходимо создать экземпляр сетки Muuri:

const grid = new Muuri('.grid', {
  layout: {
    rounding: false
  }
});

Ключевой момент — это возможность фильтровать элементы через метод filter(), передавая ему функцию, возвращающую true/false для каждого элемента.


Фильтрация по одному атрибуту

Для фильтрации элементов по значению атрибута можно использовать следующий подход:

function filterByCategory(category) {
  grid.filter(item => item.getElement().dataset.category === category);
}

// Пример использования:
filterByCategory('fruit'); // Покажет только элементы с data-category="fruit"

Пояснение:

  • item.getElement() возвращает DOM-элемент сетки.
  • dataset позволяет получить объект всех data-* атрибутов элемента.
  • Возвращаемое значение true сохраняет элемент в сетке, false скрывает.

Фильтрация по нескольким атрибутам

Muuri позволяет комбинировать условия для более сложной фильтрации:

function filterByCategoryAndPrice(category, price) {
  grid.filter(item => {
    const el = item.getElement();
    return el.dataset.category === category && el.dataset.price === price;
  });
}

// Пример использования:
filterByCategoryAndPrice('vegetable', 'low'); // Покажет только морковь

Это дает полную гибкость, позволяя комбинировать категории, ценовые диапазоны или любые другие данные, закодированные в data-*.


Сброс фильтрации

Чтобы показать все элементы после применения фильтров, можно использовать:

grid.filter(() => true);

Или, альтернативно, удалить фильтрующую функцию:

grid.show(grid.getItems());

Динамическая фильтрация через UI

Часто требуется фильтровать элементы через кнопки или селекты:

<button data-filter="fruit">Фрукты</button>
<button data-filter="vegetable">Овощи</button>
<button data-filter="all">Все</button>
const buttons = document.querySelectorAll('button[data-filter]');

buttons.forEach(btn => {
  btn.addEventListener('click', () => {
    const filter = btn.dataset.filter;
    if (filter === 'all') {
      grid.filter(() => true);
    } else {
      grid.filter(item => item.getElement().dataset.category === filter);
    }
  });
});

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


Фильтрация с регулярными выражениями

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

grid.filter(item => /fruit|vegetable/.test(item.getElement().dataset.category));

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


Использование нескольких фильтров одновременно

Для комбинирования нескольких фильтров удобно хранить их состояния в объекте:

const filters = {
  category: 'fruit',
  price: 'low'
};

grid.filter(item => {
  const el = item.getElement();
  const matchCategory = filters.category ? el.dataset.category === filters.category : true;
  const matchPrice = filters.price ? el.dataset.price === filters.price : true;
  return matchCategory && matchPrice;
});

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


Поддержка динамически добавляемых элементов

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

const newItem = document.createElement('div');
newItem.classList.add('item');
newItem.dataset.category = 'fruit';
newItem.dataset.price = 'medium';
newItem.innerHTML = '<div class="item-content">Банан</div>';

grid.add(newItem);

// Применяем текущий фильтр снова
grid.filter(item => item.getElement().dataset.category === 'fruit');

Muuri автоматически интегрирует новые элементы в текущую сетку и фильтры.


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

  • Использовать кэширование: если фильтры сложные, кэшировать значение dataset для каждого элемента при инициализации.
  • Минимизировать DOM-операции: Muuri обновляет позиции только для видимых элементов, поэтому скрытые элементы не замедляют рендеринг.
  • Комбинировать фильтры и сортировку: можно сначала отфильтровать элементы, а затем отсортировать их с помощью sort().

Заключение по работе с data-* фильтрацией

  • data-* атрибуты позволяют хранить метаданные непосредственно в элементах DOM.
  • grid.filter() принимает функцию, возвращающую true/false для каждого элемента.
  • Поддерживаются фильтры по одиночным атрибутам, комбинациям, регулярным выражениям и динамическим состояниям.
  • Фильтрация совместима с добавлением новых элементов и сортировкой.

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