为什么jQuery的.animate()在完成动画之前运行“完整”功能?

时间:2013-08-29 14:29:39

标签: javascript jquery animation

我看到这个问了好几个地方,但大多数要么解决,要么这个人的代码不能证明这一点。我并没有真正计划使用jQuery .annimate()以每像素1毫秒向下滚动每个像素,但只是为了演示问题,这是我的代码:

window.stopscrolling = 0;

function scrollMore(id) {
   stopscrolling++;
   if (stopscrolling < 100) {
      var y = $(window).scrollTop();
      if ($("#"+id).offset().top != y){
         //console.log(y);
         if ($("#"+id).offset().top > y) {
             $('html, body').animate({
                scrollTop: y+1
             }, 1, "linear", function(){scrollMore(id);});
         }
         else {
             $('html, body').animate({
                scrollTop: y-1
             }, 1, "linear", function(){scrollMore(id);});
         }
      }
   }
}

如果您将其复制并粘贴到Chrome控制台中,并按以下方式运行:scrollMore(“#itemId”),窗口将向下滚动约5个像素,同时向下滚动100个。

取消注释console.log将显示它像这样运行:像素0一次,像素1四次,两次八次,三次十六次,四次32次,五次37次;共计98次。

我也在if中尝试了这种语法,它给了我相同的结果:

if ($("#"+id).offset().top > y) {
     $('html, body').animate({
        scrollTop: y+1
     },
     {
        duration : 1,
        easing: "linear",
        complete: function(){scrollMore(id)}
    });
 } 

我意识到我可以使用以下代码按ID滚动到某个项目,但我的项目会滚动,因此最终会滚动到错误的位置。

$('html, body').animate({
    scrollTop: $("#"+id).offset().top
    }, 2000);

所以问题是,为什么jQuery在完成动画之前运行“完整”功能,当文档明确指出它运行之后?当然,我能做些什么呢?

1 个答案:

答案 0 :(得分:3)

几周前我遇到了类似的问题。当您尝试使用$('html, body').animate();等语法为多个元素设置动画时,jQuery实际上会分别为两个元素激活animate函数。这意味着您添加的回调参数function(){scrollMore(id)}实际上被调用了两次。这意味着当html完成动画时,它会在body的动画完成之前触发它的回调,然后body的回调也会在它完成之后触发事情。我相信那是多个意外的控制台日志的来源。

有几种方法可以解决这个问题,但我想说最简单的方法是创建一个变量来告诉回调是否有人被解雇了。类似的东西:

var animated = false;

$('html, body').animate({
       scrollTop: y+1
    },
    {
       duration : 1,
       easing: "linear",
       complete: function(){

          if (!animated) {
              animated = true;
              scrollMore(id);
          }

       }
    }
);