🎯 Ejercicio Integrador
Pon en práctica todo lo aprendido: clases, manipulación del DOM y eventos. Construye un sistema completo desde cero.
Desafío: Catálogo de Productos con Carrito
Crea una tienda online donde los usuarios puedan ver productos, añadirlos al carrito y ver el total.
Requisitos del ejercicio:
Parte 1: Clases
- ▸ Crear clase
Producto - ▸ Propiedades: nombre, precio, icono, descripción
- ▸ Método
render()que retorne el HTML de la tarjeta
Parte 2: DOM
- ▸ Crear al menos 4 productos con datos diferentes
- ▸ Renderizar las tarjetas en un contenedor
- ▸ Crear una sección para el carrito de compras
Parte 3: Eventos
- ▸ Botón "Añadir al carrito" en cada producto
- ▸ Usar delegación de eventos
- ▸ Actualizar el carrito dinámicamente
Parte 4: Funcionalidades
- ▸ Calcular el total del carrito
- ▸ Mostrar cantidad de productos en el carrito
- ▸ Botón para vaciar el carrito
💡 Consejos antes de empezar
1. Planifica primero
Antes de escribir código, piensa en la estructura: ¿Qué propiedades tiene un producto? ¿Cómo será el HTML de cada tarjeta?
2. Hazlo paso a paso
No intentes hacer todo a la vez. Orden sugerido:
- Crea la clase Producto
- Crea algunos productos y muéstralos en consola
- Implementa el método render()
- Renderiza los productos en el DOM
- Añade los eventos
- Implementa la lógica del carrito
3. Usa iconos/emojis
Puedes usar https://via.placeholder.com/200 para las imágenes de los productos.
🚀 Archivos base del proyecto
Este ejercicio se trabaja con archivos separados para practicar la modularización. Crea los siguientes archivos en una carpeta:
⚡ Importante
- • Usa
type="module"en el script para poder usarimport/export - • Abre con Live Server (no directamente desde el archivo)
- • Completa las partes marcadas con
// TODO:en app.js
1. Archivo HTML (index.html)
Este es el archivo HTML completo. Observa que enlaza un CSS externo y carga el JavaScript como módulo:
1<!DOCTYPE html>2<html lang="es">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Tienda Online</title>7 <link rel="stylesheet" href="styles.css">8</head>9<body>10 <div class="container">11 <h1>🛒 Mi Tienda Online</h1>12 13 <!-- Resumen del carrito -->14 <div class="carrito-header">15 <div>16 <h2>Carrito de Compras</h2>17 <p>Productos: <span id="cantidad-carrito">0</span></p>18 </div>19 <button class="btn btn-vaciar" id="vaciar-carrito">Vaciar Carrito</button>20 </div>21 22 <!-- Lista de productos (se llenará con JavaScript) -->23 <div id="productos"></div>24 25 <!-- Carrito -->26 <div id="lista-carrito">27 <h2>Tu Carrito:</h2>28 <div id="items-carrito">29 <p class="vacio">El carrito está vacío</p>30 </div>31 <div id="total">Total: $0</div>32 </div>33 </div>34 35 <!-- ⚡ Importante: type="module" para usar import/export -->36 <script type="module" src="app.js"></script>37</body>38</html>2. Archivo JavaScript principal (app.js)
Aquí va tu código JavaScript. Completa las secciones marcadas:
1import { Producto } from './Producto.js';2 3// 1. CREAR PRODUCTOS4// TODO: Crea un array con al menos 4 productos usando la clase Producto5// Ejemplo: new Producto(1, 'Laptop Gaming', 1299.99, '💻', 'Potente laptop para gaming')6const productos = [7 // Añade aquí tus productos...8];9 10// 2. ESTADO DE LA APLICACIÓN11let carrito = [];12 13// 3. RENDERIZAR PRODUCTOS14// TODO: Completa esta función para mostrar los productos en el DOM15function renderizarProductos() {16 const contenedor = document.querySelector('#productos');17 contenedor.innerHTML = '';18 19 // Recorre el array de productos y usa el método render() de cada uno20 // ...21}22 23// 4. FUNCIONES DEL CARRITO24// TODO: Completa esta función para añadir productos al carrito25function agregarAlCarrito(id) {26 // 1. Busca el producto por id27 // 2. Verifica si ya existe en el carrito28 // 3. Si existe, incrementa la cantidad29 // 4. Si no existe, añádelo con cantidad 130 // 5. Llama a actualizarCarrito()31}32 33// TODO: Completa esta función para actualizar la vista del carrito34function actualizarCarrito() {35 const itemsCarrito = document.querySelector('#items-carrito');36 const cantidadEl = document.querySelector('#cantidad-carrito');37 const totalEl = document.querySelector('#total');38 39 // 1. Calcula la cantidad total de productos (usa reduce)40 // 2. Calcula el precio total (usa reduce)41 // 3. Actualiza el DOM con los valores42}43 44// TODO: Completa esta función para vaciar el carrito45function vaciarCarrito() {46 carrito = [];47 actualizarCarrito();48}49 50// 5. EVENTOS51// TODO: Añade un evento click al contenedor de productos usando delegación52// Usa e.target.classList.contains('btn-agregar') para detectar el botón53// Obtén el id con: parseInt(e.target.dataset.id)54 55// TODO: Añade un evento click al botón "Vaciar Carrito"56 57// 6. INICIALIZAR58// TODO: Llama a renderizarProductos() para mostrar los productos al cargar la página3. Clase Producto (Producto.js) - Punto de partida
Esta clase ya está completa y puedes usarla como está. Estudia cómo funciona:
1// Clase Producto2export class Producto {3 constructor(id, nombre, precio, icono, descripcion) {4 this.id = id;5 this.nombre = nombre;6 this.precio = precio;7 this.icono = icono;8 this.descripcion = descripcion;9 }10 11 // Método que retorna el HTML de la tarjeta12 render() {13 return `14 <div class="producto-card">15 <div class="icono icono-${this.id}">${this.icono}</div>16 <h3>${this.nombre}</h3>17 <p class="descripcion">${this.descripcion}</p>18 <div class="precio">$${this.precio}</div>19 <button class="btn btn-agregar" data-id="${this.id}">20 Añadir al Carrito21 </button>22 </div>23 `;24 }25}4. Estilos CSS (styles.css)
Aquí tienes los estilos completos con gradientes para los iconos:
1* {2 margin: 0;3 padding: 0;4 box-sizing: border-box;5}6 7body {8 font-family: Arial, sans-serif;9 background-color: #f3f4f6;10 padding: 20px;11}12 13.container {14 max-width: 1200px;15 margin: 0 auto;16}17 18h1 {19 text-align: center;20 color: #1f2937;21 margin-bottom: 30px;22}23 24.carrito-header {25 background-color: #3b82f6;26 color: white;27 padding: 15px;28 border-radius: 10px;29 margin-bottom: 30px;30 display: flex;31 justify-content: space-between;32 align-items: center;33}34 35#productos {36 display: grid;37 grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));38 gap: 20px;39 margin-bottom: 30px;40}41 42.producto-card {43 background-color: white;44 border-radius: 10px;45 padding: 20px;46 box-shadow: 0 2px 8px rgba(0,0,0,0.1);47 transition: transform 0.2s;48}49 50.producto-card:hover {51 transform: translateY(-5px);52}53 54.producto-card .icono {55 width: 100%;56 height: 200px;57 display: flex;58 align-items: center;59 justify-content: center;60 font-size: 80px;61 border-radius: 8px;62 margin-bottom: 15px;63}64 65/* Gradientes para los iconos */66.icono-1 { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }67.icono-2 { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }68.icono-3 { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }69.icono-4 { background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); }70.icono-5 { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); }71.icono-6 { background: linear-gradient(135deg, #30cfd0 0%, #330867 100%); }72 73.producto-card h3 {74 color: #1f2937;75 margin-bottom: 10px;76}77 78.producto-card .descripcion {79 color: #6b7280;80 font-size: 14px;81 margin-bottom: 15px;82 min-height: 40px;83}84 85.producto-card .precio {86 color: #3b82f6;87 font-size: 24px;88 font-weight: bold;89 margin-bottom: 15px;90}91 92.btn {93 width: 100%;94 padding: 10px;95 border: none;96 border-radius: 5px;97 cursor: pointer;98 font-size: 16px;99 font-weight: bold;100 transition: background-color 0.2s;101}102 103.btn-agregar {104 background-color: #10b981;105 color: white;106}107 108.btn-agregar:hover {109 background-color: #059669;110}111 112.btn-vaciar {113 background-color: #ef4444;114 color: white;115 padding: 10px 20px;116}117 118.btn-vaciar:hover {119 background-color: #dc2626;120}121 122#lista-carrito {123 background-color: white;124 padding: 20px;125 border-radius: 10px;126 margin-bottom: 20px;127}128 129.item-carrito {130 display: flex;131 justify-content: space-between;132 padding: 10px 0;133 border-bottom: 1px solid #e5e7eb;134}135 136#total {137 font-size: 24px;138 font-weight: bold;139 color: #1f2937;140 text-align: right;141 margin-top: 15px;142}143 144.vacio {145 text-align: center;146 color: #9ca3af;147 padding: 20px;148}📁 Estructura final del proyecto
mi-tienda/
├── index.html ✅ HTML con estructura completa
├── styles.css 🎨 CSS (crea los estilos básicos)
├── Producto.js ✅ Clase completa (punto de partida)
└── app.js ⚙️ Completa las funciones marcadas con TODO 📚 Conceptos aplicados
Clases (POO)
- Constructor con parámetros
- Método
render()que genera HTML - Crear múltiples instancias con
new
Manipulación del DOM
-
querySelectorpara seleccionar elementos -
innerHTMLpara insertar HTML dinámico -
textContentpara actualizar texto
Eventos
-
addEventListenerpara clicks - Delegación de eventos en contenedor padre
-
data-attributes para pasar información
Otros conceptos
- Arrays con
map,find,reduce - Arrow functions
- Template literals para HTML