【问题标题】:Callback of .animate() gets called twice jquery.animate() 的回调被调用两次 jquery
【发布时间】:2012-02-06 03:00:43
【问题描述】:

由于我添加了一些scrollTop-animation,我的回调的某些部分被调用了两次:

$('html, body').animate({scrollTop: '0px'}, 300,function() {
    $('#content').load(window.location.href, postdata, function() {                 
        $('#step2').addClass('stepactive').hide().fadeIn(700, function() {
            $('#content').show('slide',800);                    
        });
    });
});

它似乎只是重复了.show(),至少我不觉得load().fadeIn() 也会被第二次调用。 .show() 第一次完成后会立即重复。顺便说一下,将 scrollTop 动画速度设置为 0 并没有帮助!

我认为它与动画队列有关,但我不知道如何找到解决方法,尤其是为什么会发生这种情况。

【问题讨论】:

    标签: jquery callback


    【解决方案1】:

    要获得完成多个元素动画的单个回调,请使用延迟对象。

    $(".myClass").animate({
      marginLeft: "30em"
    }).promise().done(function(){
      alert("Done animating");
    });
    

    当您对集合调用 .animate 时,集合中的每个元素都会单独设置动画。当每一个都完成时,回调被调用。这意味着如果您为八个元素设置动画,您将获得八个回调。当这八个元素上的所有动画完成时,.promise().done(...) 解决方案会为您提供一个回调。这确实有一个副作用,如果在这八个元素中的任何一个上发生了任何 其他 动画,则回调将不会发生,直到这些动画也完成。

    有关PromiseDeferred Objects 的详细说明,请参阅jQuery API。

    【讨论】:

    • 这解决了关于我们想要在完成动画时做什么的问题,但问题是两次调用并为此获得了 +1,但我不知道动画过程是否被调用两次?!
    • 动画过程不会被调用两次,回调会为每个选定的元素调用一次。因此,如果您选择 8 个列表项并将它们动画到左侧,则回调将执行 8 次。当所有 8 个完成时,我的解决方案会为您提供一个回调。
    • @KevinB,很好的解决方案,它也帮助解决了我自己的回调问题。谢谢。
    • 我认为这是一个有趣的答案,但不幸的是它产生了意想不到的后果。承诺不只是延迟回调执行,直到 jQuery 集合的元素完成当前动画(这会很棒)。只有在集合的所有未决动画完成后才能解决。因此,如果在第一个动画仍在运行时设置了第二个动画,则用于第一个动画的回调直到第二个动画结束后才会运行。见this bin
    • 没错,它等待所有当前动画完成所选元素。只等待在这个链中启动的那些是不够聪明的(也不应该是)
    【解决方案2】:

    animate 为您调用animate 的集合中的每个元素 调用一次回调:

    如果提供,startstepprogresscompletedonefailalways 回调将在每个元素的基础上调用...

    由于您要为两个元素(html 元素和 body 元素)设置动画,因此您会收到两个回调。 (对于任何想知道为什么 OP 为两个元素设置动画的人,这是因为动画在某些浏览器上适用于 body,而在其他浏览器上适用于 html。) p>

    要在动画完成时获得 单个 回调,animate 文档指出您使用 promise 方法获取动画队列的承诺,然后使用 then 来排队回调:

    $("html, body").animate(/*...*/)
        .promise().then(function() {
            // Animation complete
        });
    

    (注意:Kevin B 在第一次提出问题时指出了这一点 in his answer。直到四年后我才发现它丢失了,添加了它,然后......然后看到了 Kevin 的回答.请给他应得的爱。我想这是公认的答案,我应该把它留在里面。)

    这是一个显示单个元素回调和整体完成回调的示例:

    jQuery(function($) {
    
      $("#one, #two").animate({
        marginLeft: "30em"
      }, function() {
        // Called per element
        display("Done animating " + this.id);
      }).promise().then(function() {
        // Called when the animation in total is complete
        display("Done with animation");
      });
    
      function display(msg) {
        $("<p>").html(msg).appendTo(document.body);
      }
    });
    <div id="one">I'm one</div>
    <div id="two">I'm two</div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

    【讨论】:

    • 是的,这就是原因,实际上我不记得为什么我曾经写过html, body。是时候重新启动我的大脑了。谢谢
    • 可能是因为仅 html 动画在 Webkit 中不起作用,而仅 body 在 Opera 中不起作用。两者都使用将确保它始终有效,但会在 Firefox 中触发两次回调。 (我可能弄错了浏览器...)
    • html 对于 IE 是必需的,对于大多数其他浏览器,回调将触发两次。我正在尝试解决同样的问题。
    • 我通过创建一个标志来处理它:var ranOne = false; $('body,html').animate({ scrollTop: scrollTo }, scrollTime, 'swing', function () { if (ranOne) { ...action... ranOne = false; } else { ranOne = true; } }); 感觉很老套,但首先必须使用“body,html”有点老套,所以。 (抱歉缺少换行符,猜测 cmets 没有显示)
    • 难以置信!我花了几个小时试图让我的滚动动画与 $("html,body") 一起正常工作,这样它就不会触发两次,而这个答案救了我!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多