Cómo hacer escuchar múltiples miniaturas con eventos del ratón JavaScript
Spanish (Español) translation by Richter Domagas (you can also view the original English article)
En este tutorial tendremos un buen rato con eventos del mouse JavaScript mediante la construcción de algo útil e interesante: miniaturas que, cuando se cernía sobre la muestra una selección de diferentes libros electrónicos.
Aquí está la demo que vamos a construir (mueva el ratón sobre cada miniatura):
Cada miniatura muestra los correspondientes libros electrónicos ocultados debajo, dependiendo de la posición del cursor. Es la forma ideal de dar un adelanto de lo que está disponible (en este caso en la biblioteca de libros electrónicos Envato Tuts+).
Como construimos esto utilizaremos CSS Grid Layout y el evento mousemove
de JavaScript, entre otras cosas.
1. El marcado HTML
La marca que vamos a usar es bastante sencilla; una lista desordenada llana con algunas imágenes de igual tamaño dentro de cada uno de los elementos de lista (cards).
<ul class="cards"> <li class="card"> <img src="IMG_SRC" alt=""> <!-- 4 more images here --> </li> <li class="card"> <img src="IMG_SRC" alt=""> <!-- 3 more images here --> </li> <li class="card"> <img src="IMG_SRC" alt=""> <!-- 2 more images here --> </li> <li class="card"> <img src="IMG_SRC" alt=""> <!-- 1 more image here --> </li> </ul>
2. El CSS
Ahora, con respecto a los estilos CSS, son importantes dos cosas:
- Definimos la lista desordenada como un contenedor de grid y dar de objetos de la lista de
width: 25%
. En lugar de CSS grid, podría utilizar caja flexible o el método de disposición preferido. - Ocultar visualmente y posición absolutamente todas las imágenes dentro de los elementos de lista, aparte de la primera.
A continuación se muestran las reglas CSS que se aplican a nuestra un demo:
.cards { display: grid; grid-gap: 20px; grid-template-columns: repeat(4, 1fr); } .card { position: relative; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.5); } .card:hover { cursor: pointer; } .card img:not(:first-of-type) { position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: 0; } .card img.is-visible { opacity: 1; }
Con un par de otros estilos de restablecer (quitar las viñetas de la lista desordenada, dando al cuerpo un color de fondo etc.) terminamos con esto:
3. El JavaScript
Vamos a agregar las siguientes dos líneas para que cuando los activos de la página, la función init
se ejecuta. También nos lo activan cada vez que se resized la window del navegador.
window.addEventListener("load", init); window.addEventListener("resize", init);
Dentro de esta function, ocurre una serie de cosas; primero nos de bucle a través de las cards.
function init() { const cards = document.querySelectorAll(".card"); cards.forEach(el => { // actions here }); }
Bucle las Child Images
A continuación, para cada card recuperamos el número de child images sin tener en cuenta la primera imagen.
Nota: la primera imagen es visible por defecto y no absolutamente posicionado.
const numOfChildImages = el.querySelectorAll("img:not(:first-of-type)").length;
Si hay al menos una child image, hacemos lo siguiente:
- Calcular el width de la card (el ancho de la primera imagen) y...
- ...split la card en partes iguales dividiendo el width con el número de child images.
if (numOfChildImages > 0) { const { width } = el.getBoundingClientRect(); const parts = width / numOfChildImages; }
Para entender mejor esto, supongamos que la primera card es 235px amplia. Esta card contiene cuatro imágenes (recuerda que ignorar la primera imagen), por lo que la división 235px/4 nos dará 58.75px. ¿Cuál es el papel de este número? Bien, crea nuestras gamas, por lo que al hover de la card, seguir la posición X del ratón, compruebe su gama y finalmente mostrar la imagen correspondiente.
Para nuestro ejemplo simple, aquí están los intervalos generados:
Posición X del Ratón | Imagen para Mostrar |
---|---|
0<X≤58.75px | 1st |
58.75px<X≤117.5px | 2nd |
117.5px<X≤176.25px | 3rd |
176.25px<X≤235px | 4th |
Tenga en cuenta la columna "Imagen para Mostrar" muestra la imagen que debe aparecer de la piscina de las imágenes de cuatro hijos (una vez más nos excluyen la primera imagen visible).



Ahora que sabemos que los requisitos, vamos a convertir en código. Todavía dentro del bucle escucha para el evento mousemove
.
// hover cards el.addEventListener("mousemove", e => { // do stuff here });
Cuando este evento, realizamos las siguientes acciones:
- Obtiene la coordenada X del puntero del ratón en relación con la card "hovered" y no en relación con la ventana del navegador.
- Quitar la clase
is-visible
de todas las card images. - Mostrar la imagen apropiada dependiendo de la posición del ratón (ver tabla anterior para ver un ejemplo).
Parte del código que implementa el comportamiento anterior es el siguiente:
el.addEventListener("mousemove", e => { //1 const xPos = e.pageX - el.offsetLeft; //2 removeIsVisibleClass(); //3 switch (numOfChildImages) { case 1: if (xPos > 0 && xPos <= parts) { addClass(el, "img:nth-child(2)"); } break; case 2: if (xPos > 0 && xPos <= parts) { addClass(el, "img:nth-child(2)"); } else if (xPos > parts && xPos <= parts * 2) { addClass(el, "img:nth-child(3)"); } break; // more cases below } });
Como se puede ver, hay dos funciones personalizadas. En primer lugar, el removeIsVisibleClass
función que es responsable de la eliminación de la class is-visible
de la imagen correspondiente. En segundo lugar, el más general addClass
función que es responsable de agregar la class is-visible
en la imagen de destino.
Aquí está su firma:
function removeIsVisibleClass() { if (document.querySelector("img.is-visible")) { document.querySelector("img.is-visible").classList.remove("is-visible"); } } function addClass(parent, child, className = "is-visible") { parent.querySelector(child).classList.add(className); }
Hasta ahora, hemos visto lo que sucede cada vez pasa el cursor sobre una card. Ahora veamos el escenario opuesto. En otras palabras, lo que debería suceder si dejamos flotando sobre una card. En este caso se debe mostrar la primera imagen inicial:
// inside cards loop el.addEventListener("mouseleave", () => { removeIsVisibleClass(); });
4. Soporte del navegador
Nuestra un demo debería funcionar bien en la mayoría de los navegadores de escritorio. Algunas notas de embargo:
- La demostración hace uso de CSS Grid y el bucle
foreach
que no son compatibles por todos los navegadores. Hay soluciones alternativas para los dos casos si usted prefiere usar una suplencia. - La demo funciona de forma similar en todas las pantallas / dispositivos y no está optimizada para pequeñas pantallas / táctil dispositivos. Para nuestra demostración sencilla que está muy bien, pero en un proyecto real puede restringir esta implementación sólo las pantallas más grandes (o dispositivos no táctiles).
Por último, como de costumbre, utilizamos Babel para compilar el código ES6 hasta ES5.
Conclusión
En este tutorial, hemos conseguido crear un interesante efecto de hover aprovechando eventos de ratón de JavaScript. Que te has inspirado para crear algo sorprendente.
Para tomar las cosas más lejos, os animo a construir una función reutilizable que controlará el código repetitivo dentro de la sentencia switch
. ¡Publicar un comentario si asumes el reto!