如何使用 jQuery 按顺序为多个元素设置动画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1218152/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 10:56:11  来源:igfitidea点击:

How can I animate multiple elements sequentially using jQuery?

jqueryanimationqueue

提问by lnvrt

I thought it would be simple but I still can't get it to work. By clicking one button, I want several animations to happen - one after the other- but now all the animations are happening at once. Here's my code - can someone please tell me where I'm going wrong?:

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

$(".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");
});

采纳答案by jammus

You could do a bunch of callbacks.

你可以做一堆回调。

$(".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");        
            });
        });
    });
});

回答by redsquare

Queue only works if your animating the same element. Lord knows why the above got voted up but it will not work.

Queue 仅在您为相同元素设置动画时才有效。上帝知道为什么上述内容被投票通过,但这是行不通的。

You will need to use the animation callback. You can pass in a function as the last param to the animate function and it will get called after the animation has completed. However if you have multiple nested animations with callbacks the script will get pretty unreadable.

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

I suggest the followingplugin which re-writes the native jQuery animate function and allows you to specify a queue name. All animations that you add with the same queue name will be run sequentially as demonstrated here.

我建议使用以下插件重写原生 jQuery 动画函数并允许您指定队列名称。您使用相同的队列名称添加所有的动画将作为展示顺序运行这里

Example script

示例脚本

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

回答by Bill Barry

I know this is an old question, but it should be updated with an answer for newer jQuery versions (1.5 and up):

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

Using the $.whenfunction you can write this helper:

使用该$.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;
}

Then you can call it like this:

然后你可以这样称呼它:

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");        
});

回答by pgraham

A slight improvement on @schmunk's answer is to use a plain object jQuery object's queue in order to avoid conflicting with other unrelated animations:

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

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

One thing to keep in mind is that, although I have never run into problems doing this, according to the docsusing the queue methods on a plain object wrapper is not officially supported.

要记住的一件事是,虽然我从来没有遇到过这样做的问题,但根据文档,在普通对象包装器上使用队列方法不受官方支持。

Working With Plain Objects

At present, the only operations supported on plain JavaScript objects wrapped in jQuery are: .data(),.prop(),.bind(), .unbind(), .trigger() and .triggerHandler().

使用普通对象

目前,jQuery 封装的纯 JavaScript 对象支持的操作只有:.data()、.prop()、.bind()、.unbind()、.trigger() 和 .triggerHandler()。

回答by Chris Moschini

Animate Multiple Tags Sequentially

按顺序对多个标签进行动画处理

You can leverage jQuery's built-in animation queueing, if you just select a tag like body to do global queueing:

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

// 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/

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

So, here's why this works, and what it's doing:

所以,这就是为什么它有效,以及它在做什么:

  1. The call to $.globalQueue.queue()is just queueing a call to your tag's animation, but it queues it on the body tag.

  2. When jQuery hits your tag animation in the body queue, your tag's animation starts, on the queue for your tag - but the way the jQuery animation framework works, any custom animation callback causes a tag's animation queue (the body's in this case) to halt, until the custom animation calls the passed-in dequeue()function. So, even though the queues for your animated tag and body are separate, the body tag's queue is now waiting for its dequeue()to be called. http://api.jquery.com/queue/#queue-queueName-callback

  3. We just make the last queued item on the tag's queue a call to continue the global queue by calling its dequeue()function - that's what ties the queues together.

  4. For convenience the globalQueue.queuemethod returns a thisreference for easy chaining.

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

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

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

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

setInterval

设置间隔

For the sake of completeness, it's easy to land here just seeking an alternative to setInterval- that is you're not so much looking to make separate animations coordinate, as just fire them over time without the strange surge ahead in your animation caused by the way newer browsers will postpone animation queues and timers to save CPU.

为了完整起见,很容易找到替代方案setInterval- 也就是说,您不太希望制作单独的动画坐标,而只是随着时间的推移触发它们,而不会引起动画中的奇怪激增较新的浏览器将推迟动画队列和计时器以节省 CPU。

You can replace a call to setIntervallike this:

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

setInterval(doAthing, 8000);

With this:

有了这个:

/**
 * 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/

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

And avoid those awkward blasts of animation when a background tab has its animations re-enabled by the browser.

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

回答by Sean

Extending on jammus' answer, this is perhaps a bit more practical for long sequences of animations. Send a list, animate each in turn, recursively calling animate again with a reduced list. Execute a callback when all finished.

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

The list here is of selected elements, but it could be a list of more complex objects holding different animation parameters per animation.

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

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);
    });
}

回答by Lomefin

I was thinking about a backtracking solution.

我正在考虑回溯解决方案。

Maybe, you can define that every object here has the same class, for example .transparent

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

Then you can make a function, say startShowing, that looks for the first element which has the .transparentclass, animate it, remove .transparentand then call itself.

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

I can't assure the sequence but usually follows the order in which the document was written.

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

This is a function I did to try it out

这是我尝试使用的功能

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

回答by schmunk

You can also put your effects into the same queue, i.e. the queue of the BODY element.

您也可以将您的效果放入同一个队列,即 BODY 元素的队列。

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

Make sure you call dequeue() within the last effect callback.

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

回答by MrVimes

This has already been answered well (I think jammus's answer is the best) but I thought I'd provide another option based on how I do this on my website, using the delay()function...

这已经得到了很好的回答(我认为 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");
});

(replace 1000 with your desired animation speed. the idea is your delay function delays by that amount and accumulates the delay in each element's animation, so if your animations were each 500 miliseconds your delay values would be 500, 1000, 1500)

(用你想要的动画速度替换 1000。这个想法是你的延迟函数延迟了那个量并累积每个元素动画的延迟,所以如果你的动画是每 500 毫秒,你的延迟值将是 500、1000、1500)

edit: FYI jquery's 'slow' speed is also 600miliseconds. so if you wanted to use 'slow' still in your animations just use these values in each subsequent call to the delay function - 600, 1200, 1800

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

回答by Garrett

Use the queueoption:

使用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" });
});