Escribir un generador de galería de imágenes con un control deslizante incorporado



¡Buen dia amigos!

En lugar de introducción (enunciado del problema)


Todo comenzó con el estudio de los controles deslizantes de otras personas (soluciones preparadas en la red, como bxslider , owlcarousel y slick ). Algún día escribiré tutoriales detallados sobre cómo trabajar con estas herramientas (dulces sueños). Hubo un deseo de escribir su control deslizante. Sin embargo, pronto (incluso después de leer varios artículos sobre Habré), me di cuenta de que solo un control deslizante es para los débiles. Se necesita algo más radical.

Como resultado, se me ocurrió la siguiente tarea: escribir un generador de galería adaptable con un control deslizante incorporado.

Condiciones:

  • Posibilidad de cargar cualquier cantidad de imágenes (desde cualquier lugar de su disco duro).
  • La galería consta de imágenes cargadas, el marcado se forma "sobre la marcha" de conformidad con la semántica HTML5.
  • La galería se ve igualmente bien en pantallas con diferentes resoluciones.
  • Cuando hace clic en cualquier imagen, se genera un control deslizante.
  • Al generar un control deslizante, el fondo se oscurece.
  • La imagen clicada es la primera diapositiva.
  • La conmutación de diapositivas se implementa a través del DOM.
  • Las diapositivas cambian suavemente.
  • Capacidad para controlar el cambio de diapositivas mediante botones y teclado.
  • La posibilidad de volver a la galería haciendo clic en la diapositiva y el botón actuales, así como también usando el teclado.
  • JavaScript puro (todo marcado a través de JS).
  • Código mínimo

Entonces, vamos (como dijo Gagarin, yendo al espacio).

El marcado se ve así:
<div class="wrap">
    <input type="file" multiple accept="image/*">
    <button>generate gallery</button>
</div>

De las cosas interesantes, quizás, los atributos múltiples y aceptados de la etiqueta de entrada. El primer atributo le permite cargar varios archivos, el segundo establece un filtro sobre los tipos de archivos que se pueden descargar. En este caso, accept tiene el valor "image / *", lo que significa que solo se pueden cargar imágenes (cualquiera).

Inmediatamente traiga belleza (agregue estilos):
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    background: radial-gradient(circle, skyblue, steelblue);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

button {
    padding: 0.25em;
    font-family: monospace;
    text-transform: uppercase;
    cursor: pointer;
}

.darken {
    position: absolute;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
    z-index: -1;
}

.slider {
    width: 100%;
    display: inherit;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
}

figure {
    margin: 0.5em;
    width: 300px;
    display: inherit;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    transition: 0.2s;
}

figcaption {
    font-size: 1.2em;
    text-transform: capitalize;
    text-align: center;
    margin-bottom: 0.25em;
    color: #ddd;
    text-shadow: 1px 1px rgba(0, 0, 0, 0.4);
}

img {
    max-width: 80%;
    max-height: 80vh;
    cursor: pointer;
}

.button {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 30px;
    background: none;
    border: none;
    outline: none;
    filter: invert();
}

.left {
    left: 2em;
}

.right {
    right: 2em;
}

.close {
    top: 2em;
    right: 1em;
}


No hay nada de qué hablar (.darken - atenuación).

Pasando ... a JS.

Encontramos el botón y colgamos al oyente en él:
let button = document.querySelector("button");
button.addEventListener("click", generateGallery);

Todo el código adicional estará en la función generateGallery para evitar "no definido" sin retorno:
function generateGallery() {
    //    
}

Encontramos información, verificamos que no esté vacía, obtenemos una colección de archivos descargados, eliminamos .wrap y creamos un contenedor para la galería:
let input = document.querySelector("input");
// ,  input  
if(input.files.length == 0) return;
let files = input.files;
//  
let i;

//  .wrap,     
let wrap = document.querySelector(".wrap");
document.body.removeChild(wrap);

//    , ,    gallery
let slider = document.createElement("div");
slider.className = "slider";
document.body.appendChild(slider);

Ordenamos la colección de archivos, obtenemos el nombre y la dirección de cada archivo, creamos marcas, creamos subtítulos de imágenes y las imágenes mismas:
for (i = 0; i < files.length; i++) {
    let file = files[i];
    // URL.createObjectURL         ,         
    // ,   ,       
    //             ,      
    /*let src = URL.createObjectURL(file);*/

    //   
    let name = file.name;

    //   ,      img     
    let src = `img/${name}`;

    //  : figure, figcaption, img
    let figure = document.createElement("figure");
    slider.appendChild(figure);

    let figcaption = document.createElement("figcaption");

    //  ,             ,   
    // (?=\.) -  :     ,    
    //       \w,         
    let regexp = /.+(?=\.)/;
    name = name.match(regexp);
    //   ["", index: 0, input: ".jpg", groups: undefined]
    //    
    figcaption.innerText = name[0];
    figure.appendChild(figcaption);

    //  
    let img = document.createElement("img");
    img.src = src;
    figure.appendChild(img);
}

Queremos generar un control deslizante al hacer clic en la imagen. Para hacer esto, encontramos la figura completa y la colgamos en cada oyente:
let figures = document.querySelectorAll("figure");
for (i = 0; i < figures.length; i++) {
    let figure = figures[i];
    figure.addEventListener("click", () => {
        //  ,       figure,   
        generateSlider(figure);
    });
}

A continuación, trabajamos dentro de la función generateSlider:
function generateSlider(figure) {
    //  
}

Oscurecer el fondo:
darkenBack();
function darkenBack() {
    // ,   
    //  , ,   , 
    if (document.querySelector(".darken") == null) {
        let div = document.createElement("div");
        div.className = "darken";
        document.body.appendChild(div);
    } else {
        let div = document.querySelector(".darken");
        document.body.removeChild(div);
    }
}

Mostraremos una diapositiva a la vez. No olvide que el interruptor deslizante debe ser suave. Esto es fácil de lograr con transparencia y una pequeña transición. Por lo tanto, superponemos las imágenes una encima de la otra, las colocamos en el centro y hacemos que todas las imágenes, excepto la "pulsada", sean transparentes:
for (i = 0; i < figures.length; i++) {
    if (figures[i].hasAttribute("style")) {
        figures[i].removeAttribute("style");
    } else {
        figures[i].setAttribute("style", "margin: 0; width: auto; position: absolute; opacity: 0;");
    }
}

//      / 
if (figure.hasAttribute("style")) {
    figure.style.opacity = 1;
    generateButtons();
} else generateButtons();

A continuación, cree botones para cambiar las diapositivas y cierre la galería. El código resultó ser largo y aburrido (quizás no era buena idea generar botones cada vez que inicia el control deslizante):
Código de creación del botón:
function generateButtons() {
    if (document.querySelector(".buttons") == null) {
        //    
        let buttons = document.createElement("div");
        buttons.className = "buttons";
        slider.appendChild(buttons);

        //   
        let leftButton = document.createElement("button");
        leftButton.className = "button left";
        let leftImg = document.createElement("img");
        leftImg.src = "https://thebestcode.ru/media/sliderGenerator/buttons/left.png";
        leftButton.appendChild(leftImg);
        buttons.appendChild(leftButton);
        leftButton.addEventListener("click", () => changeSlide("-"));

        //   
        let rightButton = document.createElement("button");
        rightButton.className = "button right";
        let rightImg = document.createElement("img");
        rightImg.src = "https://thebestcode.ru/media/sliderGenerator/buttons/right.png";
        rightButton.appendChild(rightImg);
        buttons.appendChild(rightButton);
        rightButton.addEventListener("click", () => changeSlide("+"));

        //    
        let closeButton = document.createElement("button");
        closeButton.className = "button close";
        let closeImg = document.createElement("img");
        closeImg.src = "https://thebestcode.ru/media/sliderGenerator/buttons/close.png";
        closeButton.appendChild(closeImg);
        buttons.appendChild(closeButton);
        closeButton.addEventListener("click", () => generateSlider(figure));
    } else {
        //   ,  
        let buttons = document.querySelector(".buttons");
        slider.removeChild(buttons);
    }
}


El cambio de diapositivas se implementa utilizando la función changeSlide, que se pasa como parámetro, respectivamente, "+" o "-":
function changeSlide(e) {
    //    
    for (i = 0; i < figures.length; i++) {
        figures[i].style.opacity = 0;
    }
    if (e == "-") {
        //      ,    
        if (figure == figures[0]) {
            figure = figures[figures.length - 1];
        } else {
            figure = figure.previousElementSibling;
        }
    } else if (e == "+") {
        //      ,    
        if (figure == figures[figures.length - 1]) {
            figure = figures[0];
        } else {
            figure = figure.nextElementSibling;
        }
    }
    //    
    figure.style.opacity = 1;
}

Agregue la capacidad de cambiar diapositivas y cerrar la galería con el teclado:
document.addEventListener("keydown", e => {
    //  
    if (e.keyCode == 37 || e.keyCode == 189) {
        changeSlide("-");
    //  
    } else if (e.keyCode == 39 || e.keyCode == 187) {
        changeSlide("+");
    // esc
    } else if(e.keyCode == 27) {
        generateSlider(figure);
    }
});

Eso es todo, el generador de galería adaptable con el control deslizante incorporado está listo. Misión cumplida. Las condiciones se cumplen. Hacia el final, me di cuenta de que "código mínimo" y "todo el marcado se forma sobre la marcha utilizando JS" se contradicen entre sí, pero ya era demasiado tarde (¿es demasiado tarde para disculparse o qué pasa con One Republic?).

El resultado se puede ver aquí .

Tenga en cuenta que en Codepen usamos URL.createObjectURL para vincular a las imágenes, porque Codepen no ve la carpeta img.

Gracias por su atención.

Source: https://habr.com/ru/post/undefined/


All Articles