Проект: интернет-магазин
Всё, что мы учили, складывается в настоящий проект: данные, рендер карточек, фильтры и корзина, которая переживает перезагрузку страницы. Работаем прямо в песочнице ниже.
Шаг 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: план на ваше время
- Добавьте
input-поиск: фильтр поname.toLowerCase().includes(...); - Сделайте счётчик товаров в шапке, итоговую сумму в корзине;
- Придумайте скидку от 3 товаров — и обновите цену при рендере.
ℹ️
Тот же паттерн «массив данных → рендер → событие → перерендер» переносится в React. Проект-магазин и следующая проектная работа — одна и та же логика, другая обвязка.