Капстон: фильтрация

Основы фронтенд разработки

Капстон: фильтрация

Продолжительность: 30 мин

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

Требования

Фильтрация по категории

  • Клик по кнопке категории показывает только карточки с соответствующей категорией.
  • Кнопка «Все» сбрасывает фильтр и показывает все карточки.
  • Активная кнопка визуально выделена (класс, который вы уже стилизовали в предыдущем этапе).
  • В один момент времени активна только одна кнопка категории.

Как переключать активную кнопку. Снимите класс у всех кнопок, затем добавьте нужной:

document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active')); clickedButton.classList.add('active');
js

Поиск по тексту

  • Ввод текста в строку поиска фильтрует карточки по полям name и description.
  • Поиск нечувствителен к регистру.
  • Поиск работает одновременно с фильтром категории: если выбрана категория «Музей» и введён текст «эрм», показываются только музеи, в названии или описании которых есть «эрм».
  • При очистке поля поиска карточки возвращаются к предыдущему состоянию (с учётом активного фильтра категории).

Состояние «ничего не найдено»

  • Если ни одна карточка не подходит под текущие фильтры, в сетке должно отображаться сообщение «Ничего не найдено» с подсказкой сбросить поиск.
  • Рядом с сообщением — кнопка «Сбросить», которая очищает поле поиска и снимает фильтр категории.

Архитектура

  • Не удаляйте и не добавляйте карточки при каждом изменении фильтра. Лучший подход — держать все карточки в DOM и управлять их видимостью через CSS. Это быстрее и проще.
  • Вся логика фильтрации — одна функция, которая вызывается и при смене категории, и при вводе в поиск. Не дублируйте код.

Как связать всё вместе. Центральная идея — одна функция applyFilters, которая читает текущее состояние и решает, какие карточки показать:

function applyFilters() { const query = state.searchQuery.toLowerCase(); const category = state.activeCategory; document.querySelectorAll('.card').forEach(card => { const id = Number(card.dataset.id); const attraction = state.attractions.find(a => a.id === id); const matchesCategory = category === 'Все' || attraction.category === category; const matchesSearch = !query || attraction.name.toLowerCase().includes(query) || attraction.description.toLowerCase().includes(query); card.hidden = !(matchesCategory && matchesSearch); }); // показать/скрыть состояние "ничего не найдено" const anyVisible = [...document.querySelectorAll('.card')].some(c => !c.hidden); emptyState.hidden = anyVisible; }
js

Обработчики событий только обновляют state и вызывают applyFilters():

searchInput.addEventListener('input', (e) => { state.searchQuery = e.target.value; applyFilters(); }); filtersContainer.addEventListener('click', (e) => { const btn = e.target.closest('.filter-btn'); if (!btn) return; state.activeCategory = btn.dataset.category; // обновить активную кнопку applyFilters(); });
js

Обратите внимание на btn.dataset.category — при создании кнопок фильтрации добавляйте атрибут data-category="Музей", чтобы потом легко его читать.

Продвинутое задание — debounce

Поиск запускается при каждом нажатии клавиши. Если данных много, это может тормозить браузер. Реальное решение — debounce: функция-обёртка, которая откладывает выполнение до тех пор, пока пользователь не перестанет печатать (обычно 300–400 мс).

Реализуйте debounce самостоятельно — это небольшая функция, которую полезно уметь писать:

Подсказка. debounce принимает функцию и задержку, возвращает новую функцию. Каждый вызов новой функции сбрасывает предыдущий таймер и запускает новый. Выполнение происходит только когда таймер «добежал» до конца.

function debounce(fn, delay) { let timer; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); }; } // Использование: searchInput.addEventListener('input', debounce((e) => { state.searchQuery = e.target.value; applyFilters(); }, 300));
js

Ожидаемый результат

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

Это платный урок

Купите полный доступ к курсу чтобы просматривать данный контент

Основы фронтенд разработки

Полный курс по основам веб-разработки с нуля: HTML, CSS и JavaScript. Вы сверстаете адаптивный лендинг, освоите анимации и работу с DOM, а в финале соберёте самостоятельный проект — интерактивный путеводитель по Санкт-Петербургу.

4990 Скидка 20%
3990

Безопасные платежи обрабатываются сервисом Юкасса

Комментарии

Войдите, чтобы оставить комментарий