Empêchez le déclenchement d'un événement de défilement par un scrollTop animé lors de l'utilisation de jQuery

Je travaille sur un plugin de glissière d'une page, et j'ai un rappel d'événement de défilement qui contient un scrollTop animé, déclenchant l'événement de défilement à nouveau et se coinçant dans une boucle. J'ai essayé quelques choses comme des drapeaux, mais aucun ne semble fonctionner pour moi.

Cela émule quelque chose comme ça:

Http://alvarotrigo.com/fullPage/examples/scrollBar.html

Dans le cas où le défilement est limité par des étapes fixes, sautons à l'élément précédent ou suivant, qui occupent tous la hauteur totale de la page.

Le code est le suivant:

 function pageDown() { // Some stuff, not important if (currentIndex+1 === pageCount) nextIndex = 0; else nextIndex = currentIndex+1; nextPage = $pages.eq(nextIndex); // Important stuff $('html body').animate({ scrollTop: nextPage.offset().top }, 400, function() {preventScroll=false}); } function pageUp() { // Some stuff, not important if (currentIndex === 0) nextIndex = pageCount-1; else nextIndex = currentIndex-1; nextPage = $pages.eq(nextIndex); // Important stuff $('html body').animate({ scrollTop: nextPage.offset().top }, 400, function() {preventScroll=false}); } var lastScroll = 0, preventScroll = false; $(window).on('scroll', function() { var currentScroll = $(window).scrollTop(); if(!preventScroll) { preventScroll = true; if (currentScroll > lastScroll) pageDown(); else pageUp(); } lastScroll = currentScroll; }); 

Le principal problème auquel j'ai assisté lors de la vérification de ce problème est le retour complete des feux animate de jQuery avant l'événement final de scroll qu'il génère. Notez que cela ne se produit que lorsque vous faites défiler vers le bas pour une raison quelconque.

Après avoir expérimenté un verrou de 2 étapes, où j'ai utilisé un drapeau avec 3 états pour annuler cet événement de scroll final, qui a fonctionné assez bien, j'ai exploré davantage car il était moins coopératif avec la logique de survol qui est présente dans votre code d'origine (en sautant à L'extrémité opposée en arrivant à une fin).

Je suis arrivé avec le code suivant, qui enregistre la position cible à atteindre et ignore tous les événements de scroll tant que la position actuelle ne correspond pas à la cible.

Cela implique également la logique de renversement et doit être combiné avec le HTML et le CSS associés pour fonctionner correctement, car nous avons besoin d'espace vide (un seul pixel de chaque côté ici) pour permettre qu'un événement de scroll soit déclenché en haut et en bas. Nous commençons également un premier défilement pour positionner correctement le premier élément et permettre au renversement de fonctionner immédiatement.

J'espère que les commentaires dans le code fourniront les informations supplémentaires nécessaires pour comprendre la logique utilisée.

Une démonstration de travail est disponible dans ce jsfiddle

HTML:

 <div class="pageScroller"> <div class="bumper"></div> <div class="page" style="background-color:red;"></div> <div class="page" style="background-color:green;"></div> <div class="page" style="background-color:blue;"></div> <div class="page" style="background-color:violet;"></div> <div class="page" style="background-color:cyan;"></div> <div class="bumper"></div> </div> 

CSS:

 html, body { height:100%; margin:0; padding:0; } .pages { padding:1px 0; background-color:yellow; } .pageScroller, .page { height:100%; } .bumper { height:1px; } 

JavaScript:

 var $pages = $('.page'); var currentIndex = 0; var lastScroll = 0; var currentScroll = 0; var targetScroll = 1; // must be set to the same value as the first scroll function doScroll(newScroll) { $('html, body').animate({ scrollTop: newScroll }, 400); } $(window).on('scroll', function() { // get current position currentScroll = $(window).scrollTop(); // passthrough if(targetScroll == -1) { // no target set, allow execution by doing nothing here } // still moving else if(currentScroll != targetScroll) { // target not reached, ignore this scroll event return; } // reached target else if(currentScroll == targetScroll) { // update comparator for scroll direction lastScroll = currentScroll; // enable passthrough targetScroll = -1; // ignore this scroll event return; } // get scroll direction var dirUp = currentScroll > lastScroll ? false : true; // update index currentIndex += (dirUp ? -1 : 1); // reached before start, jump to end if(currentIndex < 0) { currentIndex = $pages.length-1; } // reached after end, jump to start else if(currentIndex >= $pages.length) { currentIndex = 0; } // get scroll position of target targetScroll = $pages.eq(currentIndex).offset().top; // scroll to target doScroll(targetScroll); }); // scroll to first element $(window).scrollTop(1)