Faites défiler l’élément sur la page, puis exécutez le rappel.

J’essaie d’utiliser .animate de jQuery pour faire défiler un élément sur une page, puis exécuter un rappel.

Après avoir cherché, j’ai trouvé cette fonction:

 function scrollToElement(selector, callback){ var animation = {scrollTop: $(selector).offset().top}; $('html,body').animate(animation, 'slow', 'swing', callback); } 

Ceci fait défiler correctement jusqu’à l’élément défini par ‘selector’, mais le rappel est appelé deux fois (car $('html,body') contient 2 éléments).

J’ai essayé de changer

 $('html,body').animate 

à:

 $(document).animate 

et:

 $(window).animate 

mais, aucun de ceux-ci ne font rien.

J’ai aussi essayé de changer la fonction pour ceci:

 $('html').animate(animation, 'slow', 'swing', function(){ $('body').animate(animation, 'slow', 'swing', callback); }); 

mais, cela a obligé le navigateur à exécuter la 1ère animation puis la 2ème, il fallait donc attendre que les deux s’exécutent avant que le rappel ne soit exécuté (je ne veux pas de cela).

J’ai découvert que $('body').scrollTop() ne fonctionne que dans Chrome, et $('html').scrollTop() ne fonctionne que dans Firefox.

Donc, y a-t-il un moyen (sans avoir besoin de télécharger un plugin jQuery) de faire défiler un élément spécifique à la fois dans Chrome et Firefox (je me fiche de IE), et de faire exécuter un rappel (une fois)?

EDIT :

J’ai fait un correctif grossier en faisant un booléen pour vérifier si le rappel a déjà été exécuté et, le cas échéant, ne l’exécutez pas à nouveau.

 function scrollToElement(selector, callback){ var animation = {scrollTop: $(selector).offset().top}; var callback_running = false; $('html,body').animate(animation, 'slow', 'swing', function(){ if(typeof callback == 'function' && !callback_running){ callback_running = true; callback(); } }); } 

Je pense que cela devrait fonctionner aussi

 function scrollToElement(selector, callback){ var animation = {scrollTop: $(selector).offset().top}; $('html,body').animate(animation, 'slow', 'swing', function() { if (typeof callback == 'function') { callback(); } callback = null; }); } 

Si vous utilisez jQuery 1.5 (ou pouvez effectuer une mise à niveau), vous pouvez utiliser la nouvelle syntaxe $.Deferred .

 $.fn.scrollToElement = function(selector, callback) { var def = new $.Deferred(), el = this; $('html, body').animate({scrollTop: $(selector).offset().top}, 'slow', 'swing', def.resolve); if (callback) { def.promise().done(function(){ callback.call(el); }); } }; $('html, body').scrollToElement('#foo', function() { alert('done scrolling'); }); 

Parce qu’un object différé ne peut être résolu qu’une seule fois, vous ne pouvez pas avoir plus d’un appel au rappel.

Avez-vous essayé d’utiliser

 $(document.body).animate( ... ) 

que diriez-vous d’utiliser une DIV qui s’étend sur tout le corps du document et de faire l’animation sur cette DIV à la place? vous ne pouvez pas être sûr du nombre de problèmes de navigateur que vous pouvez trouver autrement (par exemple, combien de navigateurs n’animeraient pas HTML ni BODY, par exemple)

Vous devez éviter d’animer les éléments HTML et body. L’animation de votre page fonctionnera correctement sur tous les navigateurs, anciens ou modernes, et le rappel sera exécuté une fois (comme il se doit) par l’ajout d’une condition simple à votre fonction.

 function scrollToElement(selector, callback){ var scrollElem='html'; //animate body for webkit browsers that don't support html animation if($.browser.webkit){ scrollElem='body'; } var animation = {scrollTop: $(selector).offset().top}; $(scrollElem).animate(animation, 'slow', 'swing', callback); } 

Seul webkit ne prend pas en charge l’animation “html”. Vous devez donc modifier la variable “scrollElem” en conséquence. En outre, le défilement d’un seul élément (html ou body) fonctionne beaucoup mieux avec les anciens navigateurs (par exemple, les versions précédentes d’Opera).