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

时间:2022-11-28 09:30:41

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

9 个解决方案

#1


24  

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

#2


28  

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

仅当您动画相同的元素时,队列才有效。上帝知道为什么上面的人被投了票但是行不通。

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 following plugin 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 animate函数,并允许您指定队列名称。使用相同队列名称添加的所有动画将按顺序运行,如此处所示。

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

#3


25  

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

#4


6  

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 docs using 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(),. turigger()和.triggerHandler()。

#5


2  

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的回答,这对于长动画序列来说可能更为实用。发送一个列表,依次为每个动画制作动画,再次使用缩小列表再次调用动画。全部完成后执行回调。

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

#6


2  

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.

    对$ .globalQueue.queue()的调用只是将对标记动画的调用排队,但是它会在body标记上排队。

  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

    当jQuery在正文队列中点击您的标记动画时,标记的动画会在您的标记的队列上启动 - 但是jQuery动画框架的工作方式,任何自定义动画回调都会导致标记的动画队列(在本例中为正文)停止,直到自定义动画调用传入的dequeue()函数。因此,即使您的动画标记和正文的队列是分开的,正文标记的队列现在正在等待其dequeue()被调用。 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.

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

  4. For convenience the globalQueue.queue method returns a this reference for easy chaining.

    为方便起见,globalQueue.queue方法返回此引用以便于链接。

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 setInterval like 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.

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

#7


1  

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()。

#8


1  

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

编辑:FYI jquery的'慢'速度也是600毫秒。因此,如果您想在动画中使用'慢',请在每次后续调用延迟功能时使用这些值 - 600,1200,1800

#9


-8  

Use the queue option:

使用队列选项:

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

#1


24  

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

#2


28  

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

仅当您动画相同的元素时,队列才有效。上帝知道为什么上面的人被投了票但是行不通。

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 following plugin 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 animate函数,并允许您指定队列名称。使用相同队列名称添加的所有动画将按顺序运行,如此处所示。

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

#3


25  

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

#4


6  

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 docs using 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(),. turigger()和.triggerHandler()。

#5


2  

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的回答,这对于长动画序列来说可能更为实用。发送一个列表,依次为每个动画制作动画,再次使用缩小列表再次调用动画。全部完成后执行回调。

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

#6


2  

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.

    对$ .globalQueue.queue()的调用只是将对标记动画的调用排队,但是它会在body标记上排队。

  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

    当jQuery在正文队列中点击您的标记动画时,标记的动画会在您的标记的队列上启动 - 但是jQuery动画框架的工作方式,任何自定义动画回调都会导致标记的动画队列(在本例中为正文)停止,直到自定义动画调用传入的dequeue()函数。因此,即使您的动画标记和正文的队列是分开的,正文标记的队列现在正在等待其dequeue()被调用。 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.

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

  4. For convenience the globalQueue.queue method returns a this reference for easy chaining.

    为方便起见,globalQueue.queue方法返回此引用以便于链接。

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 setInterval like 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.

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

#7


1  

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()。

#8


1  

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

编辑:FYI jquery的'慢'速度也是600毫秒。因此,如果您想在动画中使用'慢',请在每次后续调用延迟功能时使用这些值 - 600,1200,1800

#9


-8  

Use the queue option:

使用队列选项:

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