Как я живу в jQuery без укладки обратных вызовов?
Скажем, у меня есть три div, и я бы хотел, чтобы каждый из них был анимационным, как только предыдущий закончен. В настоящее время я пишу это:
$('div1').fadeOut('slow', function() {
$('div2').fadeOut('slow', function() {
$('div3').fadeOut('slow');
});
});
Что является уродливым, но управляемым.
Теперь представьте, что у меня есть 10 различных анимаций, которые должны произойти один за другим для разных элементов. Внезапно код становится настолько неуклюжим, что его очень сложно управлять...
Здесь псевдокод для того, что я ищу:
$('div1').fadeOut('slow' { delay_next_function_until_done: true } );
$('div2').fadeOut('slow' { delay_next_function_until_done: true } );
$('div3').animate({ top: 500 }, 1000 );
Как мне это достичь?
Ответы
Ответ 1
Если вы используете последнюю версию jQuery, используйте анимацию promises:
$('div1').fadeOut('slow').promise().pipe(function() {
return $('div2').fadeOut('slow');
}).pipe(function() {
return $('div3').animate({ top: 500 }, 1000 );
});
Вы можете сделать его общим:
$.chain = function() {
var promise = $.Deferred().resolve().promise();
jQuery.each( arguments, function() {
promise = promise.pipe( this );
});
return promise;
};
var animations = $.chain(function() {
return $('div1').fadeOut('slow');
}, function() {
return $('div2').fadeOut('slow');
}, function() {
return $('div3').animate({ top: 500 }, 1000 );
});
$.when( animations ).done(function() {
// ALL ANIMATIONS HAVE BEEN DONE IN SEQUENCE
});
Все еще много закрытий функций, но сама природа Javascript. Тем не менее, это намного более естественно и намного более гибко, используя Deferreds/ Promises, поскольку вы избегаете "создания" обратных вызовов.
Ответ 2
Я делаю это, с помощью этого метода вы можете поместить все div, как хотите, только добавляя или удаляя элементы в списке var, также вы можете их переупорядочить, и вам не нужно беспокоиться о времени задержки.
var list = [ '#div1', '#div2', '...' ];
var i = 0;
function fade(cb) {
if (i < list.length) {
$(list[i]).fadeOut('slow', function() {
i++;
fade(cb);
});
} else {
cb && cb();
}
}
fade();
вы также можете добавить обратный вызов, когда процесс завершается
fade(function(){alert('end')});
Демо
Ответ 3
Когда функции завершения или обратные вызовы становятся слишком глубокими или код повторяется снова и снова, я склонен думать о решении таблицы данных с общей функцией:
function fadeSequence(list) {
var index = 0;
function next() {
if (index < list.length) {
$(list[index++]).fadeOut(next);
}
next();
}
var fades = ["div1", "div2", "div3", "div4", "div5"];
fadeSequence(fades);
И, если вы хотите использовать разные типы анимации для некоторых элементов, вы можете создать массив объектов, которые описывают, какими должны быть каждая последующая анимация. Вы можете добавить столько деталей в массив объектов, сколько было необходимо. Вы даже можете смешивать анимацию с другими синхронными вызовами метода jQuery следующим образом:
function runSequence(list) {
var index = 0;
function next() {
var item, obj, args;
if (index < list.length) {
item = list[index++];
obj = $(item.sel);
args = item.args.slice(0);
if (item.sync) {
obj[item.type].apply(obj, args);
setTimeout(next, 1);
} else {
args.push(next);
obj[item.type].apply(obj, args);
}
}
}
next();
}
// sequence of animation commands to run, one after the other
var commands = [
{sel: "#div2", type: "animate", args: [{ width: 300}, 1000]},
{sel: "#div2", type: "animate", args: [{ width: 25}, 1000]},
{sel: "#div2", type: "fadeOut", args: ["slow"]},
{sel: "#div3", type: "animate", args: [{ height: 300}, 1000]},
{sel: "#div3", type: "animate", args: [{ height: 25}, 1000]},
{sel: "#div3", type: "fadeOut", args: ["slow"]},
{sel: "#div4", type: "fadeOut", args: ["slow"]},
{sel: "#div1", type: "fadeOut", args: ["slow"]},
{sel: "#div5", type: "css", args: ["position", "absolute"], sync: true},
{sel: "#div5", type: "animate", args: [{ top: 500}, 1000]}
];
runSequence(commands);
И вот рабочая демонстрация этого второго варианта: http://jsfiddle.net/jfriend00/PEVEh/
Ответ 4
Один из способов сделать это - написать собственную вспомогательную функцию, например:
$.fn.sequentialFade = function() {
if(this.length > 0) {
var $set = $(this);
$set.eq(0).fadeOut(function() {
$set.slice(1).sequentialFade();
});
}
}
И используйте его так:
$('.div1, .div2. .div3').sequentialFade();
http://jsfiddle.net/JpNgv/
Ответ 5
попробуйте что-то вроде:
$( 'div1' ).fadeOut();
$( 'div2' ).delay( 500 ).fadeOut();
$( 'div3' ).delay( 1000 ).fadeOut();
При необходимости отрегулируйте время
Ответ 6
Используйте это:
$('#div1, #div2, #div3').each(function(index){
$(this).delay(1000 * index).hide(1000);
});
Если вы можете дать классу <div>
a:
$('.forHide').each(function(index, value){
$(this).delay(1000 * index).hide(1000);
});
- Первый элемент исчезает после 1000 * 0 = сразу с анимацией в одну секунду.
- Второй элемент исчезает после 1000 * 1 = Одна секунда с анимацией в одну секунду.
- Третий элемент исчезает после 1000 * 2 = Две секунды с анимацией в одну секунду.
- ...
- ...
- Элемент n исчезает после 1000 * n = n секунд с анимацией в одну секунду.
Live DEMO
Ответ 7
Обратный звонок - друг, не отталкивайте его. Есть способы упростить их. Вот один из них
$('div1').fadeOut('slow', div2)
function div3() { $('div3').fadeOut('slow'); }
function div2() { $('div2').fadeOut('slow', div3); }