2009-07-07 5 views
25

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

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

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

Помогает ли jQuery «queue»? Я не мог понять documentation для очереди.

Пример, JQuery:

function One() { 
     $('div#animateTest1').animate({ left: '+=200' }, 2000); 
    } 
    function Two() { 
     $('div#animateTest2').animate({ width: '+=200' }, 2000); 
    } 

// Call these functions sequentially so that the animations 
// in One() run b/f the animations in Two() 
    One(); 
    Two(); 

HTML:

<div id="animatetest" style="width:50px;height:50px;background-color:Aqua;position:absolute;"></div> 
    <div id="animatetest2" style="width:50px;height:50px;background-color:red;position:absolute;top:100px;"></div> 

Спасибо.

EDIT: Я пробовал его с timers, но я думал, что есть лучший способ сделать это.

EDIT # 2:

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

+0

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

+0

Есть способ сделать это сейчас в jquery, используя систему обещаний. Пожалуйста, проверьте мой ответ здесь: http://stackoverflow.com/a/18216474/726239 – Shaunak

ответ

37

код JQuery Очередь не так хорошо задокументированы, как это могло быть, но основная идея заключается в следующем:

$("#some_element").queue("namedQueue", function() { 
    console.log("First"); 
    var self = this; 
    setTimeout(function() { 
    $(self).dequeue("namedQueue"); 
    }, 1000); 
}); 

$("#some_element").queue("namedQueue", function() { 
    console.log("Second"); 
    var self = this; 
    setTimeout(function() { 
    $(self).dequeue("namedQueue"); 
    }, 1000); 
}); 

$("#some_element").queue("namedQueue", function() { 
    console.log("Third"); 
}); 

$("#some_element").dequeue("namedQueue"); 

Если запустить этот код, вы увидите «First» в консоли, пауза из 1s, см. «Второе» в консоли, еще одна пауза в 1 секунду и, наконец, увидеть «Третий» в консоли.

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

Анимации в jQuery все запускаются в очереди под названием fx. Когда вы анималируете элемент, он автоматически добавляет новую анимацию в очередь и вызывает dequeue, если анимация не выполняется. Вы можете вставить свои собственные обратные вызовы в очередь fx, если хотите; вам просто нужно вызвать dequeue вручную в конце (как и при использовании любой другой очереди).

+0

$ ('div # myDiv1'). Queue ('fx', fn1); $ ('div # myDiv2'). Queue ('fx', fn2); Обратите внимание, что они выполняются параллельно, а не последовательно. Поэтому, если у вас есть две функции, с анимацией() на разных элементах, они также будут выполняться параллельно. Таким образом, просто использование очередей не позволит выполнить последовательное выполнение. – user120242

+0

Если вы используете глобальный объект, а не отдельные селекторы до .queue, он будет – methodin

+0

только для цепочки функций с эффектами, мы можем использовать систему обещаний, которая реализует мой .promise() в jQuery. Ответьте здесь, например: http://stackoverflow.com/a/18216474/726239 – Shaunak

0

Насколько интервал анимации уже определен в 2000 мс, вы можете сделать второй вызов с задержкой в ​​2000 мс:

One(); 
SetTimeout(function(){ 
    Two(); 
}, 2000); 
+0

Я знаю, что могу использовать таймеры или setTimeout, но я думал, что есть какая-то очередь, в которую я мог бы включить свои функции. – orandov

+0

... и не беспокоиться о времени. – trusktr

2

Предполагая, что вы хотите сохранить One и Two как отдельные функции, вы могли бы сделать что-то как это:

function One(callback) { 
    $('div#animateTest1').animate({ left: '+=200' }, 2000, 
     function(e) { callback(); }); 
} 
function Two() { 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 

// Call these functions sequentially so that the animations 
// in One() run b/f the animations in Two() 
    One(Two); 
+0

Что произойдет, если параметр обратного вызова, который был передан, равен «null»? Будет ли это работать? – orandov

+0

Нет, вы должны купировать некоторые ошибки обработки там. Я написал это в поле редактирования SO, не задумываясь над обработкой ошибок или попыткой запустить его. – marcc

+0

Я не пытался критиковать ваши навыки обработки ошибок. :) Я просил b/c, когда функции будут вызываться реальным пользователем, на самом деле нажмите ссылку, чтобы не было обратного вызова (null). Только когда код будет автоматизировать этапы, возникнет необходимость в обратном вызове. – orandov

2

Я бы запустить второй в качестве функции обратного вызова:

$('div#animateTest1').animate({ left: '+=200' }, 2000, function(){ 
    two(); 
}); 

, который будет запускать два(), когда заканчивается первая анимация, если у вас больше анимаций в тайм-очереди для таких случаев, я использую jquery timer plugin вместо setTimeout(), что очень удобно в некоторых случаях.

+0

что не так с SetTimeout? и как этот плагин делает это лучше, если внутри он использует указанный setTimeout? – redsquare

+0

@redsquare $ .animate уже создает таймер, так почему бы не сохранить ваш код сухим и использовать его вместо этого? Нет необходимости делать несколько таймеров. –

3

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

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

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

+0

Я думаю, что ваша идея сломается, если функция, стоящая в очереди, асинхронна, и если автор хочет ждать, пока асинхронная функция будет ждать, прежде чем запускать следующую функцию в списке. – SolutionYogi

2

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

Чтобы обернуть функцию, вам необходимо знать о the apply function. Функция apply принимает объект для области видимости и массив аргументов. Таким образом вам не нужно ничего знать о функциях, которые вы обертываете.

0

Ниже будет работать и не будет ошибкой, если обратный вызов является недействительным:

function One(callback) 
{ 
    $('div#animateTest1').animate({ left: '+=200' }, 2000, 
     function() 
     { 
      if(callback != null) 
      { 
       callback(); 
      } 
     } 
    ); 
} 
function Two() 
{ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 

var callback = function(){ Two(); }; 
One(callback); 
0

@TrippRitter должен приложить .call обратного вызова

One = function(callback){ 
    $('div#animateTest1').animate({ left: '+=200' }, 2000, function(){ 
     if(typeof callback == 'function'){ 
      callback.call(this); 
     } 
    }); 
} 

Two = function(){ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 

One(function(){ 
    Two(); 
}); 

, но его так же, как делает следующий

$('div#animateTest1') 
    .animate({ left: '+=200' }, 2000, 
    function(){ 
     Two(); 
    }); 

Two = function(){ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 
-1

Вместо создания функции простой способ можно найти здесь:

$('#main').animate({ "top": "0px"}, 3000, function() 
    { $('#navigation').animate({ "left": "100px"}, 3000, function() 
     { 
      alert("Call after first and second animation is completed."); 
     }) 
    } 
); 

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

+0

Это не отвечает на вопрос. Этот вопрос требует, чтобы вы использовали две отдельные функции. Вы не всегда объединяете анимацию вместе, иногда можно связать пользовательские функции. – trusktr

1

Более безопасный и 100% рабочий способ заключается в использовании переменной и if-ветвей. В приведенном ниже примере мы выполняем 4 задания, которые занимают 1 секунду, после задания мы хотим запустить функцию f2.

<html><body> 
<div id="a" class="a" /> 
<script type="text/javascript"> 
var jobs = 0; 
function f1() { 
job(); 
job(); 
job(); 
job();  
}; 

function f2() { 
    if(jobs >3) 
     l("f2"); 
}; 

<!------------------------- -> 
function job() { 
    setTimeout(function() { 
     l("j"); 
     jobs+=1; 
     f2(); 
    }, 1000); 
} 
function l(a) { 
    document.getElementById('a').innerHTML+=a+"<br />"; 
}; 
f1(); 


</script></body></html> 
1

Действительно простое исправление.

function One() { 
     $('div#animateTest1').animate({ left: '+=200' }, 2000, Two); 
    } 
    function Two() { 
     $('div#animateTest2').animate({ width: '+=200' }, 2000); 
    } 

// Call these functions sequentially so that the animations 
// in One() run b/f the animations in Two() 
    One(); 
//We no longer need to call Two, as it will be called when 1 is completed. 
    //Two(); 
0
$('div#animateTest1').animate({left: '+=200'},2000, 
function(){ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 
); 
0

Копирование и вставка ............ 7/9/2013

<!doctype html> 
<html lang="en"> 
    enter code here<head> 
    <meta charset="utf-8"> 
    <title>jQuery.queue demo</title> 
    <style> 
    div { margin:3px; width:40px; height:40px; 
     position:absolute; left:0px; top:30px; 
     background:green; display:none; } 
    div.newcolor { background:blue; } 
    </style> 
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script> 
</head> 
<body> 

    <button id="start">Start</button> 
    <button id="stop">Stop</button> 
    <div></div> 
<script> 
    $("#start").click(function() { 
     $("div").show("slow"); 
     $("div").animate({left:'+=200'},5000); 
     jQuery.queue($("div")[0], "fx", function() { 
     $(this).addClass("newcolor"); 
     jQuery.dequeue(this); 
     }); 
     $("div").animate({left:'-=200'},1500); 
     jQuery.queue($("div")[0], "fx", function() { 
     $(this).removeClass("newcolor"); 
     jQuery.dequeue(this); 
     }); 
     $("div").slideUp(); 
    }); 
    $("#stop").click(function() { 
     jQuery.queue($("div")[0], "fx", []); 
     $("div").stop(); 
    }); 
</script> 

</body> 
</html> 
2

Как насчет всего что-то подобное?

var f1 = function() {return $(SELECTOR1).animate({ 'prop': 'value' }, 1000)}; 
var f2 = function() {return $(SELECTOR2).animate({ 'prop': 'value' }, 1000)}; 
var f3 = function() {return $(SELECTOR3).animate({ 'prop': 'value' }, 1000)}; 

$.when(f1).then(f2).then(f3); 
0

Хотя ответ Иегуда Кац является технически правильным будет раздуваться очень быстро с более крупной сложной анимации.

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

демо: https://jessengatai.github.io/okaynowthis.js/

Решения вашей проблемы с помощью okaynowthis.js будет выглядеть следующим образом:

$('window').load(function(){ 

    // keyframe 1 
    $('body').okaynowthis('keyframe',0,function(){ 
     $('div#animateTest1').animate({ left: '+=200' }, 2000); 
     // + anything else you want to do 

    // keyframe 2 (with 2 seconds delay from keyframe 1) 
    }).okaynowthis('keyframe',2000,function(){ 
     $('div#animateTest2').animate({ left: '+=200' }, 2000); 
     // + anything else you want to do 

    }); 

});