Остановка отдельных анимаций jQuery

У меня есть несколько анимаций на одном объекте, и мне нужно остановить определенную анимацию, а не все. Это не похоже на метод .stop().

Например, при одновременной анимации непрозрачности и ширины, возможно, мне придется отменить анимацию непрозрачности, все еще завершая анимацию ширины. Казалось бы, это невозможно, но я надеюсь, что кто-то знает трюк или API-запрос, который мне не хватает.

Примечание. Я не говорю о анимации с очередями, я ищу одновременно анимацию нескольких атрибутов с возможностью остановить некоторые из этих анимаций атрибутов после того, как они уже начались.

Ответ 1

Я ненавижу быть парнем, который отвечает на его собственный вопрос (большое спасибо за подробные ответы и вложил в него мозговую силу!), но я нашел прямой ответ. По-видимому, существует параметр для метода .animate(), называемого "queue", который по умолчанию имеет значение true, но вы можете установить значение false, чтобы сразу появилась ваша анимация.

Это означает, что, установив очередь в false, вы можете запускать несколько анимаций, используя отдельные вызовы, не дожидаясь окончания предыдущего. Еще лучше, если вы попытаетесь запустить анимацию для свойства, которое уже анимировано, второе будет переопределять первое. Это означает, что вы можете остановить анимацию свойств, просто "оживляя" ее текущее значение с длительностью 0, используя очередь "false".

Пример:

$myElement = $("#animateElement");
$myElement.animate({width: 500}, {duration: 5000});
$myElement.animate({height: 500}, {duration: 5000, queue: false});
// ... Wait 2 seconds ...
$myElement.animate({width: $myElement.width()}, {duration: 0, queue: false});

Другим вариантом был предложен любезный вкладчик jQuery, который ответил на мой запрос расширения. Это позволяет использовать функцию шага в анимации (функции шагов вызывается в каждой точке анимации, и вы можете управлять параметрами анимации на основе любых критериев, которые вы хотите). Хотя это также могло решить проблему, я чувствовал, что это намного более грязно, чем опция "queue: false".

Ответ 2

Подумав об этом немного сложнее об этом, я понял, что то, что вы пытаетесь сделать, непросто выполнимо из-за того, как анимации обрабатываются в jQuery.

Поскольку анимация управляется очередью, невозможно запустить параллельные анимации на один и тот же элемент, не будучи в одной и той же функции.

То есть

$(element).animate(aThing, aTime);
          .animate(anotherThing, anotherTime);

не будет запускаться параллельно. aThing закончится в aTime, а затем еще одно нажатие для другого времени.

Таким образом, вы можете выполнить только несколько изменений, включив их в одну и ту же функцию:

$(element).animate({aThing: aValue, anotherThing: anotherValue}, aTime);

Вот краткое объяснение анатомии того, как функции анимации обрабатываются в jQuery.

Объект таймера назначается элементу на время анимации:

function t( gotoEnd ) {
    return self.step(gotoEnd);
}

t.elem = this.elem;
jQuery.timers.push(t);

Когда вы вызываете функцию остановки, она удаляет таймер из таймеров:

// go in reverse order so anything added to the queue during the loop is ignored
for ( var i = timers.length - 1; i >= 0; i-- ) {
    if ( timers[i].elem === this ) {
        if (gotoEnd) {
            // force the next step to be the last
            timers[i](true);
        }

        timers.splice(i, 1);
    }
}

Таким образом, нет способа удалить определенное свойство функции анимации, так как сам таймер убит.


Единственный способ, которым я мог бы подумать об этом, - отслеживать время и продолжительность начала, повторно запустив анимацию и остановить текущий.

var start = $.now();
var duration = 5000;

$(element).animate({opacity: '0.5', width: '500px'}, duration);

...

var remaining = duration - ($.now() - start);
$(element).animate({opacity: '0.5', remaining)
          .stop();

Ответ 3

Вместо одной анимации вы можете разбить ее на несколько меньших анимаций (например, живая непрозрачность от 0 до 20%, а затем оживить от 20 до 40%, затем 40-60% и т.д.), а вместо .stop() - анимация, вы просто не запускаете ее снова?

Ответ 4

ОБНОВЛЕНИЕ 2013

Как и в jQuery 1.7, вы можете использовать .animate() с именованной очередью и использовать .stop(queuename) для остановки только этих анимаций в очереди.

http://api.jquery.com/animate/
http://api.jquery.com/stop/

Ответ 5

Я использую плагин цикла jQuery для анимации дюжины слайд-шоу на одной странице с использованием различных типов анимации (салфетки, тасования, масштабирование и т.д.). Затем у меня был свой собственный маленький script, чтобы слегка погладить изображения, когда вы наводили курсор на каждое слайд-шоу:

# This code stops all current animations on an element

$(".box img").hover(
    function(){
        $(this).stop().fadeTo("slow",0.7);
    },
    function(){
        $(this).stop().fadeTo("fast",1);
    }
);

Проблема заключалась в том, что функция .stop() также останавливала плагин цикла в нем - мои салфетки, перетасовки и масштабирование резко останавливались на полпути через их анимацию, оставляя страницу сломанной и нерабочей. Решение заключалось в том, чтобы реализовать свою ложную идею в очереди:

# This code suited me better - it leaves the other running animations untouched

$(".box img").hover(
    function(){
        $(this).animate({opacity: 0.7}, {duration: 1000, queue: false});
    },
    function(){
        $(this).animate({opacity: 1}, {duration: 250, queue: false});
    }
);