Saltar a contenido

WA2 · Ejercicios de DOM y eventos avanzados

Los ejercicios WA2.1 a WA2.4 son de JavaScript sin DOM: escríbelos en un .js y ejecútalos con node archivo.js; tu salida debe ser idéntica al resultado esperado, obtenido ejecutando la solución modelo con Node de verdad. Los WA2.5 y WA2.6 son de DOM: se hacen en una página HTML y se comprueban en el navegador; no tienen salida de consola. Los marcados con ⭐ son más difíciles.

Ejercicio WA2.1

Leer filtros de la URL. Escribe leerFiltros con URL y URLSearchParams.

// Recibe una URL (texto) y devuelve un objeto con sus parámetros:
//  - «pagina» y «precioMax» pasan a NÚMERO si existen;
//  - «q» se queda como texto (o "" si no existe);
//  - «etiquetas» es un array con TODOS los valores de «etiqueta» (vacío si no hay).
function leerFiltros(url) {
  // ...
}

Para comprobarlo:

console.log(leerFiltros("https://tienda.es/lista?q=caf%C3%A9&pagina=2&precioMax=15.5&etiqueta=bio&etiqueta=oferta"));
console.log(leerFiltros("https://tienda.es/lista"));

Resultado esperado (ejecutado con Node):

{
  q: 'café',
  etiquetas: [ 'bio', 'oferta' ],
  pagina: 2,
  precioMax: 15.5
}
{ q: '', etiquetas: [] }
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

function leerFiltros(url) {
  const p = new URL(url).searchParams;
  const filtros = { q: p.get("q") ?? "", etiquetas: p.getAll("etiqueta") };
  if (p.has("pagina")) filtros.pagina = Number(p.get("pagina"));
  if (p.has("precioMax")) filtros.precioMax = Number(p.get("precioMax"));
// ... (resto de la solución bloqueado)

Ejercicio WA2.2

Construir una URL. Escribe urlDe sin pegar cadenas a mano.

// Construye la URL de búsqueda a partir de un objeto de estado {q, pagina, etiquetas}.
// Solo incluye «q» si no está vacío, «pagina» si es mayor que 1, y una «etiqueta» por cada elemento del array.
// La base es siempre https://tienda.es/lista
function urlDe(estado) {
  // ...
}

Para comprobarlo:

console.log(urlDe({ q: "té verde & menta", pagina: 3, etiquetas: ["bio", "oferta"] }));
console.log(urlDe({ q: "", pagina: 1 }));

Resultado esperado (ejecutado con Node):

https://tienda.es/lista?q=t%C3%A9+verde+%26+menta&pagina=3&etiqueta=bio&etiqueta=oferta
https://tienda.es/lista
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

function urlDe({ q = "", pagina = 1, etiquetas = [] }) {
  const url = new URL("https://tienda.es/lista");
  if (q) url.searchParams.set("q", q);
  if (pagina > 1) url.searchParams.set("pagina", pagina);
  for (const e of etiquetas) url.searchParams.append("etiqueta", e);
// ... (resto de la solución bloqueado)

Ejercicio WA2.3

Un bus de eventos. Escribe crearBus con un Map y Set.

// crearBus devuelve { escuchar(nombre, fn), emitir(nombre, datos) } SIN usar EventTarget:
//  - escuchar devuelve una FUNCIÓN que, al llamarla, deja de escuchar;
//  - emitir llama a todas las funciones de ese nombre con los datos, y devuelve cuántas se llamaron.
function crearBus() {
  // ...
}

Para comprobarlo:

const bus = crearBus();
const dejar = bus.escuchar("saludo", n => console.log("hola,", n));
bus.escuchar("saludo", n => console.log("buenas,", n));
console.log(bus.emitir("saludo", "Ana"));
dejar();
console.log(bus.emitir("saludo", "Luis"));
console.log(bus.emitir("nadie", 1));

Resultado esperado (ejecutado con Node):

hola, Ana
buenas, Ana
2
buenas, Luis
1
0
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

function crearBus() {
  const oyentes = new Map();
  return {
    escuchar(nombre, fn) {
      if (!oyentes.has(nombre)) oyentes.set(nombre, new Set());
// ... (resto de la solución bloqueado)

Ejercicio WA2.4

Migrar datos guardados. Escribe migrar.

// Los datos guardados pueden estar en la versión 1 o la 2. Escribe `migrar`:
//   v1: { version: 1, nombre: "Ana Pérez" }
//   v2: { version: 2, nombre: "Ana", apellidos: "Pérez" }   (el primer espacio separa nombre y apellidos)
// Si ya es v2, se devuelve igual. Si no tiene versión o no es un objeto, devuelve { version: 2, nombre: "", apellidos: "" }.
function migrar(datos) {
  // ...
}

Para comprobarlo:

console.log(migrar({ version: 1, nombre: "Ana María Pérez Gil" }));
console.log(migrar({ version: 2, nombre: "Luis", apellidos: "Ruiz" }));
console.log(migrar({ nombre: "sin versión" }));
console.log(migrar(null), migrar("texto"));

Resultado esperado (ejecutado con Node):

{ version: 2, nombre: 'Ana', apellidos: 'María Pérez Gil' }
{ version: 2, nombre: 'Luis', apellidos: 'Ruiz' }
{ version: 2, nombre: '', apellidos: '' }
{ version: 2, nombre: '', apellidos: '' } { version: 2, nombre: '', apellidos: '' }
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

function migrar(datos) {
  const vacio = { version: 2, nombre: "", apellidos: "" };
  if (datos === null || typeof datos !== "object") return vacio;
  if (datos.version === 2) return datos;
  if (datos.version === 1) {
// ... (resto de la solución bloqueado)

Ejercicio WA2.5

Lista de la compra con delegación. (DOM: se comprueba en el navegador, no hay salida de consola.) Parte de este HTML y escribe el JavaScript para que:

  • el botón «Añadir» añada el producto escrito (si no está vacío) a la lista con un solo addEventListener para todos los botones «Quitar»,
  • al pulsar «Quitar» en cualquier fila, esa fila desaparezca (también las añadidas después),
  • el texto del producto se inserte con textContent, de forma que si escribes <b>pan</b> se vea como texto.
<input id="producto" placeholder="Producto">
<button id="anadir">Añadir</button>
<ul id="lista"></ul>
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

<input id="producto" placeholder="Producto">
<button id="anadir">Añadir</button>
<ul id="lista"></ul>
<script>
const lista = document.getElementById("lista");
const entrada = document.getElementById("producto");
<!-- ... (resto de la solución bloqueado) -->

Ejercicio WA2.6

⭐ Tarjetas que aparecen al verse. (DOM: se comprueba en el navegador.) Una página con 12 <div class="tarjeta">, cada una de 150 px de alto y con opacity: 0 al principio, debe hacer que cada tarjeta se vuelva visible (con una transición) la primera vez que entra en la pantalla, y que deje de observarse a partir de ese momento. Usa IntersectionObserver.

<style>
  .tarjeta { height: 150px; margin: 20px; background: #fde68a; opacity: 0; transition: opacity .6s; }
  .tarjeta.visible { opacity: 1; }
</style>
<!-- 12 tarjetas, creadas por script -->
<div id="contenedor"></div>
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

<style>
  .tarjeta { height: 150px; margin: 20px; background: #fde68a; opacity: 0; transition: opacity .6s; }
  .tarjeta.visible { opacity: 1; }
</style>
<div id="contenedor"></div>
<script>
<!-- ... (resto de la solución bloqueado) -->