Капстон: избранное и финальная полировка

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

Капстон: избранное и финальная полировка

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

Финальный этап. Добавляем избранное, убеждаемся что приложение работает на любом экране, и полируем детали.

Требования

Избранное

  • На каждой карточке — кнопка с иконкой сердечка для добавления в избранное.
  • Клик по сердечку добавляет или убирает место из избранного. Кнопка меняет внешний вид в зависимости от состояния.
  • Список избранных id сохраняется в localStorage и восстанавливается при перезагрузке страницы.
  • В шапке — кнопка «Избранное», которая переключает режим: показывает только избранные карточки или возвращает полный список.
  • Когда режим избранного включён и список пуст, показывайте соответствующее сообщение с призывом добавить понравившиеся места.
  • В модальном окне тоже должна быть кнопка избранного — и она должна быть синхронизирована с кнопкой на карточке (добавил в модалке → иконка на карточке тоже изменилась).

Как хранить избранное. Держите массив id в state.favourites и зеркалируйте его в localStorage. Удобно вынести в отдельные функции:

function toggleFavourite(id) { const index = state.favourites.indexOf(id); if (index === -1) { state.favourites.push(id); } else { state.favourites.splice(index, 1); } localStorage.setItem('favourites', JSON.stringify(state.favourites)); updateFavouriteButtons(id); } function isFavourite(id) { return state.favourites.includes(id); }
js

При загрузке страницы восстанавливайте из localStorage:

const saved = localStorage.getItem('favourites'); state.favourites = saved ? JSON.parse(saved) : [];
js

Синхронизация кнопок на карточке и в модалке. После каждого изменения избранного нужно обновить все кнопки, связанные с этим id. Напишите функцию updateFavouriteButtons(id), которая находит все элементы с нужным data-id и обновляет их внешний вид:

function updateFavouriteButtons(id) { const isFav = isFavourite(id); // Кнопка на карточке const card = document.querySelector(`.card[data-id="${id}"]`); if (card) { card.querySelector('.card__fav-btn').classList.toggle('active', isFav); } // Кнопка в модалке (если открыта для этого же места) if (state.currentAttractionId === id) { modalFavBtn.classList.toggle('active', isFav); } }
js

Чтобы клик по сердечку не открывал модалку. Обработчик делегирования на сетке откликается на любой клик внутри карточки. Если не остановить всплытие при клике на сердечко, сработают оба обработчика. Добавьте проверку:

grid.addEventListener('click', (e) => { if (e.target.closest('.card__fav-btn')) { const card = e.target.closest('.card'); toggleFavourite(Number(card.dataset.id)); return; // не открываем модалку } const card = e.target.closest('.card'); if (card) openModal(Number(card.dataset.id)); });
js

Адаптивность

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

  • 320px — самый узкий мобильный
  • 375px — стандартный iPhone
  • 768px — планшет
  • 1280px и шире — десктоп

Типичные проблемы, на которые стоит обратить внимание: кнопки фильтров выходят за экран, модалка не помещается по высоте, поисковая строка слишком узкая, отступы слишком большие на мобильном.

Модалка на мобильном. На маленьких экранах модальное окно часто не помещается в высоту. Чтобы решить: сделайте .modal__content с max-height: 90vh; overflow-y: auto — тогда при необходимости внутри появится прокрутка. На совсем узких экранах можно отображать модалку на весь экран: width: 100%; max-width: 100%; border-radius: 0.

Анимации

  • Карточки появляются с анимацией при первой загрузке — через @keyframes и animation-delay на основе порядкового номера карточки.
  • Переход «добавить в избранное» — анимирован (хотя бы небольшой scale или смена цвета).

Последовательная анимация карточек. При создании карточки через JavaScript задайте задержку через style:

function createCard(attraction, index) { const card = document.createElement('article'); // ... card.style.animationDelay = `${index * 0.08}s`; return card; }
js

В CSS пропишите анимацию появления:

.card { animation: fadeUp 0.4s ease-out both; } @keyframes fadeUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
css

Финальная проверка

Пройдитесь по всему приложению и убедитесь:

  • в консоли браузера нет ошибок
  • все интерактивные элементы работают как ожидается
  • при быстром вводе в поиск ничего не ломается
  • при медленном интернете (вкладка Network → дросселинг → Slow 3G) виден индикатор загрузки
  • при отключённом интернете видно сообщение об ошибке

Продвинутые задания

Web Share API — добавьте кнопку «Поделиться» в модальное окно. Если браузер поддерживает Web Share API (navigator.share), используйте его. Если нет — скопируйте ссылку в буфер обмена (navigator.clipboard.writeText). Узнайте как это работает:

prefers-reduced-motion — некоторые пользователи настраивают систему так, чтобы приложения показывали меньше анимаций. Сделайте так, чтобы все ваши анимации отключались для таких пользователей:

@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
css

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

  • кнопка сердечка на карточке добавляет и убирает из избранного
  • состояние избранного сохраняется после перезагрузки страницы
  • кнопка «Избранное» в шапке переключает режим отображения
  • при пустом избранном виден соответствующий экран
  • кнопка избранного в модалке синхронизирована с карточкой
  • приложение корректно выглядит на экранах от 320px до 1280px+
  • в консоли нет ошибок
  • карточки появляются с анимацией

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

Дальше — бесконечное поле для роста: фреймворки (React, Vue), TypeScript, серверный рендеринг, тестирование. Но фундамент теперь у вас есть.

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

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

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

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

4990 Скидка 20%
3990

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

Комментарии

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