Écrire un générateur de galerie d'images avec un curseur intégré



Bonjour mes amis!

Au lieu de l'introduction (énoncé du problème)


Tout a commencé par l'étude des curseurs d'autres personnes (solutions prêtes à l'emploi sur le réseau, comme bxslider , owlcarousel et slick ). Un jour, j'écrirai des tutoriels détaillés sur l'utilisation de ces outils (doux rêves). Il y avait un désir d'écrire votre curseur. Cependant, bientôt (y compris après avoir lu plusieurs articles sur Habré), on s'est rendu compte que juste un curseur est pour les mauviettes. Il faut quelque chose de plus radical.

En conséquence, j'ai proposé la tâche suivante: écrire un générateur de galerie adaptatif avec un curseur intégré.

Conditions:

  • Possibilité de télécharger n'importe quel nombre d'images (de n'importe où sur votre disque dur).
  • La galerie se compose d'images téléchargées, le balisage est formé "à la volée" conformément à la sémantique HTML5.
  • La galerie est tout aussi bonne sur les écrans avec différentes résolutions.
  • Lorsque vous cliquez sur une image, un curseur est généré.
  • Lors de la génération d'un curseur, l'arrière-plan est assombri.
  • L'image cliquée est la première diapositive.
  • La commutation de diapositives est implémentée via le DOM.
  • Les diapositives changent en douceur.
  • Possibilité de contrôler la commutation des diapositives à l'aide des boutons et du clavier.
  • La possibilité de revenir à la galerie en cliquant sur la diapositive et le bouton actuels, ainsi qu'en utilisant le clavier.
  • JavaScript pur (tout balisage via JS).
  • Code minimum.

Alors, allons-y (comme l'a dit Gagarine, aller dans l'espace).

Le balisage ressemble à ceci:
<div class="wrap">
    <input type="file" multiple accept="image/*">
    <button>generate gallery</button>
</div>

Parmi les choses intéressantes, peut-être, les attributs multiples et acceptés de la balise d'entrée. Le premier attribut vous permet de télécharger plusieurs fichiers, le second - définit un filtre sur les types de fichiers qui peuvent être téléchargés. Dans ce cas, accept a la valeur «image / *», ce qui signifie que seules les images (toutes) peuvent être téléchargées.

Apportez immédiatement de la beauté (ajoutez des styles):
* {
    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;
}


Il n'y a rien à dire (.darken - gradation).

Passons à JS.

Nous trouvons le bouton et accrochons l'auditeur dessus:
let button = document.querySelector("button");
button.addEventListener("click", generateGallery);

Tout le code supplémentaire sera dans la fonction generateGallery afin d'éviter "non défini" sans retour:
function generateGallery() {
    //    
}

Nous trouvons une entrée, vérifions qu'elle n'est pas vide, obtenons une collection de fichiers téléchargés, supprimons .wrap et créons un conteneur pour la galerie:
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);

Nous trions la collection de fichiers, obtenons le nom et l'adresse de chaque fichier, créons du balisage, créons des légendes d'images et les images elles-mêmes:
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);
}

Nous voulons générer un curseur en cliquant sur l'image. Pour ce faire, nous trouvons la figure entière et la suspendons à chaque auditeur:
let figures = document.querySelectorAll("figure");
for (i = 0; i < figures.length; i++) {
    let figure = figures[i];
    figure.addEventListener("click", () => {
        //  ,       figure,   
        generateSlider(figure);
    });
}

Ensuite, nous travaillons à l'intérieur de la fonction generateSlider:
function generateSlider(figure) {
    //  
}

Assombrir l'arrière-plan:
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);
    }
}

Nous afficherons une diapositive à la fois. N'oubliez pas que l'interrupteur à glissière doit être lisse. Ceci est facile à réaliser avec la transparence et une petite transition. Par conséquent, nous superposons les images les unes sur les autres, les plaçons au centre et rendons transparentes toutes les images, à l'exception de celle «cliquée»:
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();

Ensuite, créez des boutons pour changer de diapositives et fermer la galerie. Le code s'est avéré long et ennuyeux (peut-être que générer des boutons à chaque démarrage du curseur n'était pas une bonne idée):
Code de création du bouton:
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);
    }
}


La commutation des diapositives est implémentée à l'aide de la fonction changeSlide, qui est passée en paramètre, respectivement, "+" ou "-":
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;
}

Ajoutez la possibilité de changer de diapos et de fermer la galerie à l'aide du clavier:
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);
    }
});

C'est tout, le générateur de galerie adaptatif avec le curseur intégré est prêt. Mission accomplie. Les conditions sont remplies. Vers la fin, j'ai réalisé que «code minimum» et «tout le balisage est formé à la volée en utilisant JS» se contredisent, mais il était trop tard (est-il trop tard pour s'excuser ou qu'est-ce que One Republic?).

Le résultat peut être vu ici .

Notez que sur Codepen, nous utilisons URL.createObjectURL pour créer un lien vers des images, car Codepen ne voit pas le dossier img.

Merci de votre attention.

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


All Articles