web-dev-qa-db-fra.com

Concepts de curseur de boucle d'infini

Je me demande quels sont les meilleurs concepts (bon code lisible, code de pratique antiparasitaire, possibilité de réutilisation) pour construire un curseur Infinity-Image-Loop pour un site Web utilisant JavaScript/jQuery? Je ne sais pas quoi savoir comment coder le diaporama, mais quel modèle correspond aux exigences mentionnées ci-dessus . La question principale de ma question est de savoir comment organiser les images pour obtenir l’impression d’une boucle d’infini Slider. 

En regardant le code de différents curseurs, je suis tombé sur deux solutions:

-changez l'index z de toutes les images chaque fois que l'image suivante/précédente est affichée.

-changez la position de l'image dans le DOM. 

Mais examiner et comprendre le code des autres prend beaucoup de temps - c'est pourquoi je pose cette question :-)

24
user1828928

tl; dr - Exemple: http://jsbin.com/ufoceq/8/


Une approche simple pour créer un curseur d’image infinie sans trop d’efforts est la suivante: supposons, par souci de simplicité, que vous ayez des images <n> à glisser dans une boucle, de sorte qu’après la nth l'image la prochaine à visualiser est le 1st (et vice versa).

L’idée est de créer un clone de la première et de la dernière image pour que

  • le clone de la dernière image est ajouté avant la première;
  • le clone de la première image est ajouté après la dernière.

Quelle que soit la quantité de vos images, vous ne devrez ajouter qu’au maximum 2 éléments clonés.

Encore une fois pour la simplicité, disons que toutes les images ont une largeur de 100px et qu'elles sont enveloppées dans un conteneur que vous déplacez à gauche/à droite dans un masque découpé avec overflow: hidden. Ensuite, toutes les images peuvent facilement être alignées dans une rangée avec display: inline-block et white-space: nowrap définis sur le conteneur (avec flexbox, la procédure est encore plus simple).

Pour n = 4, la structure du DOM ressemblerait à ceci:

offset(px)     0       100     200     300     400     500
images         |   4c   |   1   |   2   |   3   |   4   |   1c

/*                 ^^                                       ^^
       [ Clone of the last image ]              [ Clone of the 1st image ]
*/

Au début, votre conteneur sera positionné avec left: -100px (ou aussi margin-left: -100pxou même mieux (pour des raisons de performance) } _ transform: translateX(-100px)), de sorte que le curseur puisse afficher la première image. Pour passer d'une image à une autre, vous devez appliquer une animation javascript sur la même propriété que vous avez précédemment choisie.

Lorsque votre curseur est actuellement à la 4th image, vous devez passer de l'image 4 à 1c; il est donc essentiel d'exécuter un rappel à la fin de l'animation pour repositionner rapidement le wrapper de votre curseur sur le vrai 1.st décalage d'image (par exemple, vous définissez left: -100px sur le conteneur)

Ceci est analogue lorsque votre curseur est actuellement positionné sur le 1st element: pour afficher l'image précédente, vous devez simplement exécuter une animation d'image 1 à 4c et lorsque l'animation est terminée, il vous suffit de déplacer le conteneur de sorte que le curseurth décalage d'image (vous définissez par exemple left: -400px dans le conteneur). 


Vous pouvez voir l'effet sur le violon ci-dessus: c'est le code js/jquery minimal que j'ai utilisé (bien sûr, le code peut être même optimisé pour que la largeur des éléments ne soit pas codée en dur dans le script)

$(function() {

  var gallery = $('#gallery ul'),
      items   = gallery.find('li'),
      len     = items.length,
      current = 1,  /* the item we're currently looking */

      first   = items.filter(':first'),
      last    = items.filter(':last'),

      triggers = $('button');

  /* 1. Cloning first and last item */
  first.before(last.clone(true)); 
  last.after(first.clone(true)); 

  /* 2. Set button handlers */
  triggers.on('click', function() {

    var cycle, delta;

    if (gallery.is(':not(:animated)')) {

        cycle = false;
        delta = (this.id === "prev")? -1 : 1;
        /* in the example buttons have id "prev" or "next" */  

        gallery.animate({ left: "+=" + (-100 * delta) }, function() {

            current += delta;

            /** 
             * we're cycling the slider when the the value of "current" 
             * variable (after increment/decrement) is 0 or when it exceeds
             * the initial gallery length
             */          
            cycle = (current === 0 || current > len);

            if (cycle) {
                /* we switched from image 1 to 4-cloned or 
                   from image 4 to 1-cloned */
                current = (current === 0)? len : 1; 
                gallery.css({left:  -100 * current });
            }
        });   
     }

  });
});

Comme mentionné précédemment, cette solution ne demande pas vraiment beaucoup d’efforts et de performance, comparant cette approche à un curseur normal sans boucle, elle nécessite seulement de faire deux insertions DOM supplémentaires lorsque le curseur est initialisé et une logique supplémentaire (assez triviale) gérer une boucle en arrière/en avant.

Je ne sais pas s'il existe une approche plus simple ou meilleure, mais j'espère que cela aidera quand même.

Note: si vous avez aussi besoin d'une galerie responsive, peut-être que cette réponse _ pourrait aussi vous aider

55
fcalderan

Je viens de créer le curseur d’article: consultez-le: https://github.com/lingtalfi/jItemSlider/blob/master/README.md

C'est 600 lignes de code, vous pouvez peut-être simplement le parcourir.

L'idée sous-jacente est inspirée par le curseur netflix (à partir du 24/02/2016).

Fondamentalement, il utilise des traductions de transformation CSS, car ce sont les plus rapides/lisses dans un navigateur.

http://eng.wealthfront.com/2015/05/19/performant-css-animations/

Maintenant, le concept de base derrière le mouvement de diapositive est que vous affichez uniquement la tranche visible en cours, Mais vous avez également une tranche invisible à gauche et une autre à la droite.

Et vous avez également deux éléments supplémentaires, un de chaque côté, afin que vos éléments ressemblent à ceci:

éléments précédents - élément supplémentaire précédent - éléments principaux - élément supplémentaire suivant - éléments suivants

Seuls les éléments principaux sont visibles ... Les éléments supplémentaires sont partiellement visibles ... Les éléments précédent et suivant sont invisibles.

Plus de détails ici: https://github.com/lingtalfi/jItemSlider/blob/master/doc/conception.md

Lorsque vous glissez vers la droite (par exemple), vous ajoutez essentiellement plus d’articles au côté droit, .__, puis vous les supprimez du côté gauche.

Cette technique est la meilleure que j'ai rencontrée jusqu'à présent, car vous ne gérez pas une longue liste d'éléments (utiliser le clonage Sans supprimer les éléments invisibles), ce qui peut ralentir votre animation.

Remarque: mon premier essai de ce curseur était en fait un clonage sans suppression, cela fonctionne, mais je ne l'aime pas: https://github.com/lingtalfi/jInfiniteSlider

En outre, il est basé sur les éléments (plutôt que sur les pixels) et, en fin de compte, c'est ce à quoi l'utilisateur s'attend, car Tout est toujours aligné, comme il se doit.

3
ling

Merci beaucoup de cet article! J'avais mis à jour et utilisé le code ci-dessus . J'espère que cela aidera tout le monde . Mauvais développeur.

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Directive slider</title>
    <style>
        /* 四联切换焦点图 */
        .slides-wrapper{ position: relative;  width: 100%;  margin: 10px 0; }
        .gallery { position: relative;  width: 1200px;  height: 180px;  overflow:hidden;  }
        .gallery ul {  font-size: 0;  white-space: nowrap;  position: absolute;  top: 0;  left: -1200px;  margin: 0; padding: 0;  }
        .gallery li {  display: inline-block;  vertical-align: top;  width: 1200px;  height: 180px;  white-space: normal;  }
        .gallery li img{  width: 298px;  height:180px;  padding: 1px;  }
        .gallery .arrow { background: url(/shop/templates/default/images/home_bg.png) no-repeat; background-size: 150px 223px; width: 35px; height: 70px; position: absolute; z-index: 2; top: 50px; cursor: pointer; opacity: 0;}
        .gallery .prev { background-position: 1px -92px; left: 0;}
        .gallery .next { background-position: -30px -92px; right: 0px;}
    </style>
    <style type="text/css">
        .demo_wrapper{
            margin: 0 auto;
            width: 1200px;
        }
        .demo_wrapper .title{
            text-align: center;
        }
    </style>
</head>
<body>
<div class="demo_wrapper">
    <div class="title">
        <h1>Directive slider (Published by fenmingyu)</h1>
    </div>
    <!-- demo content -->
    <div class="slides-wrapper">
        <div class="gallery" id="top_sale_gallery">
            <ul>
                <li>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-1.jpg?234" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-2.jpg?752" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-3.jpg?320" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-4.jpg?365" alt=""></a>
                </li>
                <li>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-1.jpg?852" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-2.jpg?746" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-3.jpg?525" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-4.jpg?550" alt=""></a>
                </li>
            </ul>
            <div class='arrow prev'></div>
            <div class='arrow next'></div>
        </div>
        <div class="gallery" id="top_goods_gallery">
            <ul>
                <li>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-1.jpg?793" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-2.jpg?180" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-3.jpg?550" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-4.jpg?851" alt=""></a>
                </li>
                <li>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-1.jpg?234" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-2.jpg?752" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-3.jpg?320" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-4.jpg?365" alt=""></a>
                </li>
                <li>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-1.jpg?852" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-2.jpg?746" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-3.jpg?525" alt=""></a>
                    <a href="" target="_blank" title="" style="opacity: 1;"><img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-4.jpg?550" alt=""></a>
                </li>
            </ul>
            <div class='arrow prev'></div>
            <div class='arrow next'></div>
        </div>
        <div style="clear: both;"></div>
    </div>
</div>

</body>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
    $(function() {
        $.fn.gallery = function(settings) {
            var defaults = {
                time: 3000,
                direction:1
            };
            var settings = $.extend(defaults, settings);
            var gallery_wrapper = $(this),
                gallery = gallery_wrapper.find('ul'),
                items   = gallery.find('li'),
                len     = items.length,
                current = 1,  /* the current item we're looking */
                first   = items.filter(':first'),
                last    = items.filter(':last'),
                w = gallery.find('li').width(),
                triggers = gallery_wrapper.find('.arrow');
            var show_slide = function(direction,w){
                gallery.animate({ left: "+=" + (-w * direction) }, function() {

                    current += direction;

                    /**
                     * we're cycling the slider when the the value of "current"
                     * variable (after increment/decrement) is 0 or when it exceeds
                     * the initial gallery length
                     */
                    cycle = !!(current === 0 || current > len);

                    if (cycle) {
                        /* we switched from image 1 to 4-cloned or
                         from image 4 to 1-cloned */
                        current = (current === 0)? len : 1;
                        gallery.css({left:  -w * current });
                    }
                });
            };
            var picTimer = setInterval(function() {
                        show_slide(settings.direction,w);
                    },
                    settings.time);
            return this.each(function(){

                /* 1. Cloning first and last item */
                first.before(last.clone(true));
                last.after(first.clone(true));
                /* 2. Set button handlers */
                triggers.on('click', function() {
                    if (gallery.is(':not(:animated)')) {

                        var cycle = false;
                        settings.direction = ($(this).hasClass('prev'))? -1 : 1;
                        /* in the example buttons have id "prev" or "next" */
                        show_slide(settings.direction,w);
                    }
                    clearInterval(picTimer);
                    picTimer = setInterval(function() {
                                show_slide(settings.direction,w);
                            },
                            settings.time);
                });
                /* hover show arrows*/
                show_slide(settings.direction,w);

                gallery_wrapper.hover(function() {
                    $(this).find(".arrow").css("opacity", 0.0).stop(true, false).animate({
                                "opacity": "0.3"
                            },
                            300);
                },function(){
                    $(this).find(".arrow").css("opacity", 0.3).stop(true, false).animate({
                                "opacity": "0"
                            },
                            300);
                });
            });
        };
        $('#top_goods_gallery.gallery').gallery();
        $('#top_sale_gallery.gallery').gallery({
            time: 5000,
            direction:-1
        });
    });
</script>
</html>

te et utilise ceci dans mon projet.

0
fenmingyu