Этап 2: Загрузка и рендеринг данных
Free PreviewКаркас готов. Теперь подключаем реальные данные: загружаем достопримечательности с сервера и отрисовываем карточки из JavaScript.
Требования
Загрузка данных
- При загрузке страницы делайте запрос к
https://advanced-frontend.ru/api/frontend-basics/attractions. - Пока данные грузятся, в сетке должно отображаться состояние загрузки. Минимум — текст «Загружаем...». Хорошо — скелетон-карточки (серые блоки той же формы, что настоящие карточки).
- Если запрос завершился ошибкой, показывайте сообщение об ошибке и кнопку «Повторить», которая запускает запрос заново.
- Карточки-заглушки из предыдущего этапа удалите из HTML — теперь весь контент генерируется из JavaScript.
Скелетон-карточки. Вместо текста «Загружаем...» можно вставить несколько заглушек-карточек без содержимого — просто серые прямоугольники тех же размеров с пульсирующей анимацией. Добавьте несколько
<div class="card card--skeleton"></div>через JavaScript перед запросом и стилизуйте их через CSS:.card--skeleton .card__image-wrap { background: #e0e0e0; animation: pulse 1.5s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }css
Кэширование
- После успешного получения данных сохраните их в
localStorage. - При следующей загрузке страницы проверяйте кэш: если данные есть и им менее 10 минут — используйте кэш, не делая запрос к серверу.
- Если кэш устарел — делайте новый запрос и обновляйте кэш.
Структура кэша в localStorage. Храните объект с двумя полями: сами данные и временная метка:
// Сохраняем localStorage.setItem('attractions', JSON.stringify({ data: attractions, timestamp: Date.now(), })); // Читаем и проверяем const cached = localStorage.getItem('attractions'); if (cached) { const { data, timestamp } = JSON.parse(cached); const TEN_MINUTES = 10 * 60 * 1000; if (Date.now() - timestamp < TEN_MINUTES) { // используем data } }js
Рендеринг карточек
- Напишите функцию, которая принимает объект достопримечательности и возвращает готовый DOM-элемент карточки.
- Добавляйте все карточки в DOM одним вызовом — через
DocumentFragment. - Кнопки фильтрации по категориям тоже должны генерироваться из данных, а не быть захардкожены в HTML. Соберите уникальные категории из загруженного массива и создайте кнопку для каждой из них, плюс кнопку «Все».
Как собрать уникальные категории. Объект
Setавтоматически убирает дубликаты:const categories = ['Все', ...new Set(attractions.map(a => a.category))];jsДальше проходитесь по
categoriesи создавайте кнопку для каждого элемента.
Функция создания карточки. Держите её отдельно и чистой — принимает объект, возвращает элемент. Это позволит вызывать её и при первой загрузке, и позже:
function createCard(attraction) { const card = document.createElement('article'); card.classList.add('card'); card.dataset.id = attraction.id; card.innerHTML = `...`; // ваша разметка из этапа 1 return card; } // Добавляем все карточки одним вызовом const fragment = document.createDocumentFragment(); attractions.forEach(a => fragment.append(createCard(a))); grid.replaceChildren(fragment);jsМетод
replaceChildren— удобная альтернативаinnerHTML = ''+append: он очищает контейнер и вставляет новое содержимое за один вызов.
Хранение состояния
- Держите полный массив загруженных достопримечательностей в переменной — он понадобится для фильтрации на следующем этапе.
Как хранить состояние приложения. Заведите объект
stateв начале файла — в него будете складывать всё, что нужно помнить между вызовами функций:const state = { attractions: [], // все загруженные данные activeCategory: 'Все', // активный фильтр searchQuery: '', // текущий поиск favourites: [], // id избранных (этап 5) };jsЭто проще, чем разбрасывать переменные по всему файлу, и легче расширять.
Продвинутое задание — IntersectionObserver
Если хотите пойти дальше, сделайте так, чтобы карточки появлялись с анимацией по мере того, как пользователь скроллит страницу, а не все сразу при загрузке.
Для этого используется IntersectionObserver — браузерный API, который сообщает когда элемент появляется в области видимости. Изучите его самостоятельно:
Алгоритм: карточки изначально невидимы (opacity: 0), IntersectionObserver добавляет класс visible когда карточка входит в viewport — CSS-переход делает её видимой.
Ожидаемый результат
- при открытии страницы виден индикатор загрузки
- карточки появляются после загрузки данных с сервера
- при повторной загрузке страницы данные берутся из кэша (проверьте во вкладке Network)
- кнопки фильтрации создаются динамически из полученных данных
- при сетевой ошибке видно сообщение с кнопкой «Повторить»