【问题标题】:How can I animate multiple elements sequentially using jQuery?如何使用 jQuery 为多个元素按顺序制作动画?
【发布时间】:2010-11-16 03:09:43
【问题描述】:

我认为这很简单,但我仍然无法让它工作。通过单击一个按钮,我希望发生多个动画 - 一个接一个 - 但现在所有动画都同时发生。这是我的代码 - 有人可以告诉我哪里出错了吗?:

$(".button").click(function(){
  $("#header").animate({top: "-50"}, "slow")
  $("#something").animate({height: "hide"}, "slow")
  $("ul#menu").animate({top: "20", left: "0"}, "slow")
  $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");
});

【问题讨论】:

标签: jquery animation queue


【解决方案1】:

队列仅在您为相同元素设置动画时才有效。天知道为什么上面被投票了,但它不起作用。

您将需要使用动画回调。您可以将一个函数作为最后一个参数传递给 animate 函数,它会在动画完成后被调用。但是,如果您有多个带有回调的嵌套动画,则脚本将变得非常难以阅读。

我建议使用 following 插件,它重写了原生 jQuery 动画函数并允许您指定队列名称。您添加的具有相同队列名称的所有动画都将按here 演示的顺序运行。

示例脚本

  $("#1").animate({marginTop: "100px"}, {duration: 100, queue: "global"});
  $("#2").animate({marginTop: "100px"}, {duration: 100, queue: "global"});
  $("#3").animate({marginTop: "100px"}, {duration: 100, queue: "global"});

【讨论】:

  • 是的,回调是我要建议的。
  • 感谢红方。但由于不会有很多动画,我认为不需要插件(额外的 6.26kb)。不过,我会牢记在心。
  • 两个链接似乎都坏了,你能检查一下吗@redsquare?
  • 该项目不再更新。这也不是答案。
【解决方案2】:

我知道这是一个老问题,但应该用更新的 jQuery 版本(1.5 及更高版本)的答案来更新它:

使用$.when 函数,您可以编写这个助手:

function queue(start) {
    var rest = [].splice.call(arguments, 1),
        promise = $.Deferred();

    if (start) {
        $.when(start()).then(function () {
            queue.apply(window, rest);
        });
    } else {
        promise.resolve();
    }
    return promise;
}

那么你可以这样称呼它:

queue(function () {
    return $("#header").animate({top: "-50"}, "slow");
}, function () {
    return $("#something").animate({height: "hide"}, "slow");
}, function () {
    return $("ul#menu").animate({top: "20", left: "0"}, "slow");
}, function () {
    return $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");        
});

【讨论】:

  • 这是一个非常好的模式。还有一个建议 - IE 8(至少)以不同的方式处理“参数”对象。首先,它需要成为一个真正的 Array,然后 .splice 方法需要两个参数。使用 var args = Array.prototype.slice.call(arguments); var rest = [].splice.call(args, 1, args.length-1);
  • 谢谢,这对我帮助很大。
【解决方案3】:

你可以做一堆回调。

$(".button").click(function(){
    $("#header").animate({top: "-50"}, "slow", function() {
        $("#something").animate({height: "hide"}, "slow", function() {
            $("ul#menu").animate({top: "20", left: "0"}, "slow", function() {
                $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");        
            });
        });
    });
});

【讨论】:

  • 我在我的网站上遇到了类似的问题,从那以后我就想到了使用回调,但这样做似乎有点不合适。如果您能以某种方式使用 jquery 链接来做到这一点,那就太好了。目前我使用延迟功能:动画第一件事。将第二件事延迟与我为第一件事制作动画相同的时间,然后为其制作动画......等等。
  • 但是如何同时制作动画。这将一个接一个动画。
  • 是否可以让它更通用。如果你不知道有多少元素怎么办?我尝试了for 循环,但它似乎不起作用。
  • 完全未经测试... var items = [{element: element, properties: {'top': '-50}, speed:'slow'}, ...] $('button.点击(animateQueue(items)); function animateQueue(items) { if (! items.length) { return; } var item = items.shift(); $(item.element).animate(item.properties, item.speed , animateQueue.bind(this, items)); }
  • 如果您对每个动画都进行了缓动,是否可以像同一个动画一样缓动所有动画?
【解决方案4】:

@schmunk 回答的一个小改进是使用普通对象 jQuery 对象的队列,以避免与其他不相关的动画冲突:

$({})
    .queue(function (next) {
        elm1.fadeOut('fast', next);
    })
    .queue(function (next) {
        elm2.fadeIn('fast', next);
    })
    // ...

要记住的一点是,尽管我在执行此操作时从未遇到过问题,但根据the docs,在普通对象包装器上使用队列方法不受官方支持。

使用普通对象

目前,仅支持在 jQuery 中包装的纯 JavaScript 对象上的操作 分别是:.data()、.prop()、.bind()、.unbind()、.trigger() 和 .triggerHandler()。

【讨论】:

  • 这是一个优雅的解决方案,因为它避免了深度嵌套的回调。我已经组装了一些 jsFiddle 来将其付诸实践。关于包装普通对象的支持:this official jQuery tutorial 使用相同的方法。
【解决方案5】:

你也可以将你的效果放到同一个队列中,即 BODY 元素的队列中。

$('.images IMG').ready(
   function(){
        $('BODY').queue(
            function(){
                $('.images').fadeTo('normal',1,function(){$('BODY').dequeue()});
            }
        );
    }
);

确保在最后一个效果回调中调用 dequeue()。

【讨论】:

    【解决方案6】:

    扩展 jammus 的答案,这对于长动画序列可能更实用。发送一个列表,依次为每个列表设置动画,并使用简化列表再次递归调用动画。全部完成后执行回调。

    这里的列表是选定元素的列表,但它可能是一个更复杂的对象列表,每个动画包含不同的动画参数。

    Here is a fiddle

    $(document).ready(function () {
        animate([$('#one'), $('#two'), $('#three')], finished);
    });
    
    function finished() {
        console.log('Finished');
    }
    
    function animate(list, callback) {
        if (list.length === 0) {
            callback();
            return;
        }
        $el = list.shift();
        $el.animate({left: '+=200'}, 1000, function () {
            animate(list, callback);
        });
    }
    

    【讨论】:

      【解决方案7】:

      按顺序为多个标签制作动画

      如果你只选择像body这样的标签来做全局队列,你可以利用jQuery的内置动画队列:

      // Convenience object to ease global animation queueing
      $.globalQueue = {
          queue: function(anim) {
              $('body')
              .queue(function(dequeue) {
                  anim()
                  .queue(function(innerDequeue) {
                      dequeue();
                      innerDequeue();
                  });
              });
              
              return this;
          }
      };
      
      // Animation that coordinates multiple tags
      $(".button").click(function() {
          $.globalQueue
          .queue(function() {
              return $("#header").animate({top: "-50"}, "slow");
          }).queue(function() {
            return $("#something").animate({height: "hide"}, "slow");
          }).queue(function() {
              return $("ul#menu").animate({top: "20", left: "0"}, "slow");
          }).queue(function() {
              return $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");
          });
      });
      

      http://jsfiddle.net/b9chris/wjpL31o0/

      所以,这就是它的工作原理以及它的作用:

      1. $.globalQueue.queue() 的调用只是对您的标记动画的调用进行排队,但它会将其排在正文标记上。

      2. 当 jQuery 在主体队列中点击您的标签动画时,您的标签动画会在您的标签队列中开始 - 但 jQuery 动画框架的工作方式是,任何自定义动画回调都会导致标签的动画队列(在这种情况下是主体) 停止,直到自定义动画调用传入的dequeue() 函数。因此,即使您的动画标签和正文的队列是分开的,正文标签的队列现在也在等待其dequeue() 被调用。 http://api.jquery.com/queue/#queue-queueName-callback

      3. 我们只是通过调用其dequeue() 函数来调用标签队列中最后一个排队的项目来继续全局队列 - 这就是将队列联系在一起的原因。

      4. 为方便起见,globalQueue.queue 方法返回一个 this 引用以便于链接。

      设置间隔

      为了完整起见,在这里寻找setInterval 的替代方案很容易-也就是说,您并不想让单独的动画协调,而是随着时间的推移触发它们而不会出现奇怪的激增您的动画是由较新的浏览器延迟动画队列和计时器以节省 CPU 的方式引起的。

      您可以像这样替换对setInterval 的调用:

      setInterval(doAthing, 8000);
      

      有了这个:

      /**
       * Alternative to window.setInterval(), that plays nicely with modern animation and CPU suspends
       */
      $.setInterval = function (fn, interval) {
          var body = $('body');
          var queueInterval = function () {
              body
              .delay(interval)
              .queue(function(dequeue) {
                  fn();
                  queueInterval();
                  dequeue();  // Required for the jQuery animation queue to work (tells it to continue animating)
              });
          };
          queueInterval();
      };
      
      $.setInterval(doAthing, 8000);
      

      http://jsfiddle.net/b9chris/h156wgg6/

      当背景标签的动画被浏览器重新启用时,避免那些尴尬的动画爆炸。

      【讨论】:

        【解决方案8】:

        这已经得到了很好的回答(我认为 jammus 的回答是最好的)但我想我会根据我在我的网站上使用delay() 函数的方式提供另一个选项...

          $(".button").click(function(){
             $("#header").animate({top: "-50"}, 1000)
             $("#something").delay(1000).animate({height: "hide"}, 1000)
             $("ul#menu").delay(2000).animate({top: "20", left: "0"}, 1000)
             $(".trigger").delay(3000).animate({height: "show", top: "110", left: "0"}, "slow");
        });
        

        (将 1000 替换为您想要的动画速度。想法是您的延迟函数延迟该数量并累积每个元素动画中的延迟,因此如果您的动画每 500 毫秒,您的延迟值将是 500、1000、1500)

        编辑:仅供参考 jquery 的“慢”速度也是 600 毫秒。因此,如果您仍想在动画中使用“慢”,只需在每次后续调用延迟函数时使用这些值 - 600、1200、1800

        【讨论】:

        • 这似乎不是一个非常动态的方法,因为您必须手动更新这些值。
        • 这就是我过去的做法,也是我最终来到这里的原因,即获得更好的方法,但这确实有效,您可以设置动画持续时间的变量并使用他们在延迟,所以你只需要正常更新持续时间......那么似乎没有缺点??
        • 一个简单快速的解决方案+1
        • 它要求用户知道或计算延迟时间——这不是动态的(如上所述)。
        【解决方案9】:

        我在考虑回溯解决方案。

        也许,你可以定义这里的每个对象都有相同的类,例如.transparent

        然后你可以创建一个函数,比如startShowing,它查找第一个具有.transparent 类的元素,对其进行动画处理,删除.transparent,然后调用自身。

        我无法保证顺序,但通常遵循文档编写的顺序。

        这是我尝试的一个功能

        function startShowing(){
              $('.pattern-board.transparent:first').animate(
                { opacity: 1}, 
                1000,
                function(){
                  $(this).removeClass('transparent');
                  startShowing();
                }
              );
            }
        

        【讨论】:

          【解决方案10】:

          使用queue 选项:

          $(".button").click(function(){
            $("#header").animate({top: "-50"}, { queue: true, duration: "slow" })
            $("#something").animate({height: "hide"}, { queue: true, duration: "slow" })
            $("ul#menu").animate({top: "20", left: "0"}, { queue: true, duration: "slow" })
            $(".trigger").animate({height: "show", top: "110", left: "0"}, { queue: true, duration: "slow" });
          });
          

          【讨论】:

          • @garrett,你在给出答案之前测试过吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-17
          • 2013-08-27
          • 2018-07-31
          • 1970-01-01
          • 1970-01-01
          • 2020-10-04
          • 1970-01-01
          相关资源
          最近更新 更多