Проект · Урок 18

Проект: интернет-магазин

Всё, что мы учили, складывается в настоящий проект: данные, рендер карточек, фильтры и корзина, которая переживает перезагрузку страницы. Работаем прямо в песочнице ниже.

Шаг 1: данные товаров

Каталог — просто массив объектов. Одна структура, единый рендер.

const products = [
  { id: 1, name: "Футболка",  price: 1200, category: "одежда" },
  { id: 2, name: "Кепка",     price: 900,  category: "одежда" },
  { id: 3, name: "Кружка",    price: 450,  category: "посуда" }
];

Шаг 2: рендер карточек

map превращает массив в разметку, appendChild добавляет карточки в сетку. Заодно кладём кнопке data-id — так мы узнаем, какой товар добавили.

function renderCatalog(list) {
  const grid = document.getElementById("catalog");
  grid.innerHTML = "";
  list.forEach(p => {
    const card = document.createElement("article");
    card.className = "product-card";
    card.innerHTML = `<h3>${p.name}</h3>
      <p>${p.price} ₽</p>
      <button data-id="${p.id}">В корзину</button>`;
    grid.appendChild(card);
  });
}
renderCatalog(products);

Шаг 3: фильтры

Кнопкам категорий вешаем один обработчик на контейнер (делегирование!) и фильтруем массив перед рендером.

document.getElementById("filters")
  .addEventListener("click", e => {
    const cat = e.target.dataset.filter;
    if (!cat) return;
    renderCatalog(cat === "все"
      ? products
      : products.filter(p => p.category === cat));
  });
💡
Делегирование — один слушатель на родителя вместо N на кнопках. Работает и для будущих карточек, отрисованных позже. Мысленно поблагодарите event.target.

Шаг 4: корзина в localStorage

Корзину храним как массив id+количество. После каждого изменения — сохраняем в localStorage, при загрузке — читаем обратно.

function addToCart(id) {
  cart[id] = (cart[id] || 0) + 1;
  localStorage.setItem("cart", JSON.stringify(cart));
  renderCart();
}

function loadCart() {
  return JSON.parse(localStorage.getItem("cart")) || {};
}
⚠️
localStorage хранит строки — объект кладут через JSON.stringify, читают через JSON.parse. Не забудьте обернуть чтение в try/catch: чужие данные или очищенный кэш не должны ронять страницу.

Шаг 5: план на ваше время

ℹ️
Тот же паттерн «массив данных → рендер → событие → перерендер» переносится в React. Проект-магазин и следующая проектная работа — одна и та же логика, другая обвязка.