Volver al inicio
Ejercicio Integrador

🎯 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:

  1. Crea la clase Producto
  2. Crea algunos productos y muéstralos en consola
  3. Implementa el método render()
  4. Renderiza los productos en el DOM
  5. Añade los eventos
  6. 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 usar import/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:

index.htmlhtml
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:

app.jsjavascript
1import { Producto } from './Producto.js';
2
3// 1. CREAR PRODUCTOS
4// TODO: Crea un array con al menos 4 productos usando la clase Producto
5// 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ÓN
11let carrito = [];
12
13// 3. RENDERIZAR PRODUCTOS
14// TODO: Completa esta función para mostrar los productos en el DOM
15function 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 uno
20 // ...
21}
22
23// 4. FUNCIONES DEL CARRITO
24// TODO: Completa esta función para añadir productos al carrito
25function agregarAlCarrito(id) {
26 // 1. Busca el producto por id
27 // 2. Verifica si ya existe en el carrito
28 // 3. Si existe, incrementa la cantidad
29 // 4. Si no existe, añádelo con cantidad 1
30 // 5. Llama a actualizarCarrito()
31}
32
33// TODO: Completa esta función para actualizar la vista del carrito
34function 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 valores
42}
43
44// TODO: Completa esta función para vaciar el carrito
45function vaciarCarrito() {
46 carrito = [];
47 actualizarCarrito();
48}
49
50// 5. EVENTOS
51// TODO: Añade un evento click al contenedor de productos usando delegación
52// Usa e.target.classList.contains('btn-agregar') para detectar el botón
53// 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. INICIALIZAR
58// TODO: Llama a renderizarProductos() para mostrar los productos al cargar la página

3. Clase Producto (Producto.js) - Punto de partida

Esta clase ya está completa y puedes usarla como está. Estudia cómo funciona:

Producto.jsjavascript
1// Clase Producto
2export 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 tarjeta
12 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 Carrito
21 </button>
22 </div>
23 `;
24 }
25}

4. Estilos CSS (styles.css)

Aquí tienes los estilos completos con gradientes para los iconos:

styles.csscss
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

  • querySelector para seleccionar elementos
  • innerHTML para insertar HTML dinámico
  • textContent para actualizar texto

Eventos

  • addEventListener para 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