Очередь эффектов

50

»» В данной статье используется исходный код для примеров. Сохраните эту страницу для тестирования приведенных ниже примеров.

Когда вы используете эффекты, jQuery создает для каждого выбранного элемента очередь функций, выполняющих анимацию. Каждая такая функция начинает выполняться лишь после того, как закончится выполнение предыдущей. Существует ряд методов, позволяющих получать информацию о состоянии очереди или управлять ею. Эти методы приведены в таблице ниже:

Методы для работы с очередью эффектов
Метод Описание
queue() Возвращает очередь эффектов, которые должны быть выполнены для элементов, содержащихся в объекте jQuery
queue(функция) Добавляет функцию в конец очереди
dequeue() Выполняет и одновременно удаляет из очереди первую из находящихся в ней функций для элементов, содержащихся в объекте jQuery
stop(), stop(очистка), stop(очистка, конечный_переход) Останавливает текущую анимацию
delay(продолжительность) Вставляет задержку между эффектами, находящимися в очереди

Можете сами создать очередь эффектов, объединив в обычной цепочке вызовов функции, создающие анимационные эффекты, как показано в примере ниже:

$(function() {
    
    $('form').css({"position": "fixed", "top": "70px", "z-index": "2"});
    $('h1').css({"position": "fixed", "z-index": "1", "min-width": "0"});
    
    var timespan = "slow";
    
    cycleEffects();
    
    function cycleEffects() {
            $('h1')
                .animate({left: "+=100"}, timespan)
                .animate({left: "-=100"}, timespan)
                .animate({height: 223,width: 700}, timespan)
                .animate({height: 30,width: 500}, timespan)
                .slideUp(timespan)
                .slideDown(timespan, cycleEffects);
    }   

});

Запустить пример

В этом сценарии с помощью обычной цепочки вызовов методов jQuery создается серия анимационных эффектов, применяемых к элементу h1. В последнем эффекте в качестве функции обратного вызова используется функция cycleEffects(), которая повторно запускает анимационный процесс с самого начала.

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

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

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

Отображение элементов из очереди эффектов

Для просмотра содержимого очереди эффектов можно использовать метод queue(). Правда, пользы от этого будет не очень много, поскольку очередь может содержать один из двух возможных типов объектов данных. Если эффект выполняется, то соответствующим ему элементом очереди является строковое значение inprogress. Если же эффект не выполняется, то элементом очереди является функция, которая будет вызываться.

Все эффекты jQuery выполняются функцией doAnimation(), и поэтому вам не удастся определить, какой именно будет следующая анимация. Тем не менее, приступая к работе с очередью, всегда полезно просмотреть ее содержимое. Соответствующий пример приведен ниже:

$(function() {
    
    $('h1').css({"position": "fixed", "z-index": "1", "min-width": "0"});
    $('form').remove();
    $('<table border=1></table>')
        .appendTo('body').css({
            position: "fixed", "z-index": "2",
            "border-collapse": "collapse", top: 100
        });
    
    var timespan = "slow";
    
    cycleEffects();
    printQueue();
    
    function cycleEffects() {
            $('h1')
            .animate({left: "+=100"}, timespan)
            .animate({left: "-=100"}, timespan)
            .animate({height: 223,width: 700}, timespan)
            .animate({height: 30,width: 500}, timespan)
            .slideUp(timespan)
            .slideDown(timespan, cycleEffects);
    }
    
    function printQueue() {
        var q = $('h1').queue();
        var qtable = $('table');
        qtable.html("<tr><th>Длина очереди:</th><td>" + q.length + "</td></tr>");
        for (var i = 0; i < q.length; i++) {
            var baseString = "<tr><th>" + i + ":</th><td>";
            if (q[i] == "inprogress") {
        $('table').append(baseString + "Выполняется</td></tr>");
            } else if (q[i].name == "") {
        $('table').append(baseString + q[i] + "</td></tr>");
            } else {
        $('table').append(baseString + q[i].name + "</td></tr>");
            }
        }
        setTimeout(printQueue, 500);
    }
	
});

Запустить пример

В этом примере элемент form нам не нужен, в связи с чем мы убираем его из DOM и заменяем простым элементом table, который будем использовать для отображения содержимого очереди. В код добавлена также функция printQueue(), которая периодически вызывает саму себя через определенные промежутки времени. Эта функции вызывает метод queue(), а также отображает в элементе table количество элементов в очереди и некоторую информацию о них. Как уже подчеркивалось, особой ценности эта информации не представляет, однако она позволяет получить некоторую общую картину происходящего.

При первом вызове функции cycleEffects() в очереди эффектов находится шесть элементов, первый из которых находится в состоянии выполнения. Другие элементы являются экземплярами функции doAnimation(). По завершении выполнения каждого эффекта jQuery удаляет соответствующий элемент из очереди. Как только заканчивается выполнение последнего из находящихся в очереди эффектов, происходит повторный вызов функции cycleEffects(), восстанавливающей первоначальное состояние очереди, в котором в ней содержится шесть элементов.

Остановка эффектов и очистка очереди

Для остановки выполнения текущей анимации можно использовать метод stop(). Можно передать этому методу два дополнительных аргумента, каждый из которых принимает логические значения. Если первый аргумент равен true, то все другие эффекты удаляются из очереди и не будут выполняться. Указание значения true для второго дополнительного аргумента приведет к тому, что для анимируемых CSS-свойств будут установлены их целевые значения.

По умолчанию оба аргумента имеют значения false, означающие, что из очереди удаляется лишь текущий эффект и что анимируемые свойства сохраняют значения, которые они имели на момент остановки выполнения эффекта. Если очередь не очищается, то jQuery переходит к следующему эффекту и выполняет его, как обычно.

Пример использования метода stop() приведен ниже:

$(function() {
    
    $('h1').css({"position": "fixed", "z-index": "1", "min-width": "0"});
    $('form').remove();
    $('<table border=1></table>')
        .appendTo('body').css({
            position: "fixed", "z-index": "2",
            "border-collapse": "collapse", top: 100
        });
		
	$('<button>Стоп</button><button>Старт</button>')
             .appendTo($('<div style="margin-top:180px"/>').appendTo("body")
               .css({position: "fixed", "z-index": "2",
                   "border-collapse": "collapse", top: 100, left:200
               })).click(function(e) {
                   $(this).text() == "Стоп" ? $('h1').stop(true, true) : cycleEffects();
    });
    
    var timespan = "slow";
    
    ...
	
});

Запустить пример

Для демонстрации того, как работает метод stop(), в документ добавлены две кнопки. После щелчка на кнопке "Стоп" вызывается метод stop(), которому передаются два аргумента true. Это приводит к очистке оставшейся части очереди эффектов и немедленной установке целевых значений для анимируемых свойств элемента. Поскольку при использовании метода stop() функции обратного вызова не вызываются, циклическое выполнение метода cycleEffects() прерывается, и анимация прекращается. После щелчка на кнопке "Пуск" вызывается метод cycleEffects(), что приводит к возобновлению анимации.

Щелчок на кнопке "Пуск" во время выполнения анимации не смутит jQuery. Это лишь приведет к тому, что эффекты, используемые методом cycleEffects(), добавятся в очередь. Использование функций обратного вызова означает, что длина очереди эффектов будет испытывать незначительные колебания, однако это не отразится на анимации, и она будет продолжаться, как обычно.

Вставка задержки в очередь эффектов

Метод delay() позволяет вставить паузу между двумя эффектами, находящимися в очереди. Этот метод принимает один аргумент, который позволяет задать длительность паузы в миллисекундах. Пример использования метода delay() представлен ниже:

$(function() {
    
    $('form').css({"position": "fixed", "top": "70px", "z-index": "2"});
    $('h1').css({"position": "fixed", "z-index": "1", "min-width": "0"});
    
    var timespan = "slow";
    
    cycleEffects();
    
    function cycleEffects() {
            $('h1')
                .animate({left: "+=100"}, timespan)
                .animate({left: "-=100"}, timespan)
				.delay(1000)
                .animate({height: 223,width: 700}, timespan)
                .animate({height: 30,width: 500}, timespan)
				.delay(1000)
                .slideUp(timespan)
                .slideDown(timespan, cycleEffects);
    }   

});

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

Вставка функций в очередь

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

$(function() {
    
    $('form').css({"position": "fixed", "top": "70px", "z-index": "2"});
    $('h1').css({"position": "fixed", "z-index": "1", "min-width": "0"});
    
    var timespan = "slow";
    
    cycleEffects();
    
    function cycleEffects() {
            $('h1')
                .animate({left: "+=100"}, timespan)
                .animate({left: "-=100"}, timespan)
                .queue(function() {
                        $('img').fadeTo(timespan, 0).fadeTo(timespan, 1);
                        $(this).dequeue();
                })
                .animate({height: 223,width: 700}, timespan)
                .animate({height: 30,width: 500}, timespan)
                .slideUp(timespan)
                .slideDown(timespan, cycleEffects);
    }   

});

Запустить пример

Переменная this ссылается на объект jQuery, для которого был вызван этот метод. Эта возможность весьма полезна, поскольку в некоторый момент вы обязательно должны вызвать в своей функции метод dequeue(), чтобы сделать возможным выполнение следующего эффекта или функции в очереди. В этом примере метод queue() используется для добавления функции, которая выполняет анимацию прозрачности элемента с использованием метода fade().

Эффекты, включенные в пользовательскую функцию, добавляются в очереди эффектов для элементов img. Каждый элемент имеет собственную очередь, и можно управлять ими независимо одна от другой. Если хотите анимировать одновременно несколько свойств элемента, с очередью которого ведется работа, то следует использовать метод animate(). В противном случае эффекты будут лишь последовательно добавляться в очередь.

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

...
   
function cycleEffects() {
            $('h1')
                .animate({left: "+=100"}, timespan)
                .animate({left: "-=100"}, timespan)
                .queue(function(nextFunction) {
                        $('img').fadeTo(timespan, 0).fadeTo(timespan, 1);
                        nextFunction();
                })
                .animate({height: 223,width: 700}, timespan)
                .animate({height: 30,width: 500}, timespan)
                .slideUp(timespan)
                .slideDown(timespan, cycleEffects);
}   

Если не вызвать следующую функцию или метод dequeue, то дальнейшее выполнение находящихся в очереди эффектов прекратится.

Пройди тесты
Лучший чат для C# программистов