Вопрос по jquery, jquery-callback, jquery-animate, html5, jquery-ui – Как мне анимировать в JQuery без стека колбэков?

15

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

<code>$('div1').fadeOut('slow', function() {
    $('div2').fadeOut('slow', function() {
        $('div3').fadeOut('slow');
    });
});
</code>

Что некрасиво, но управляемо.

Теперь представьте, что у меня есть 10 различных анимаций, которые должны происходить одна за другойon different elements, Внезапно код становится настолько неуклюжим, что им чрезвычайно трудно управлять ...

Вот псевдокод того, что я хочу сделать:

<code>$('div1').fadeOut('slow' { delay_next_function_until_done: true } );
$('div2').fadeOut('slow' { delay_next_function_until_done: true } );
$('div3').animate({ top: 500 }, 1000 );
</code>

Как мне этого добиться?

Ваш Ответ

7   ответов
2

Один из способов сделать это - написать собственную вспомогательную функцию, например так:

$.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/

Этоdoes now.
Этоdoesn't work
Примечание: это приведет к их исчезновению в порядке следования DOM, не обязательно в том порядке, в котором вы их перечислили, потому что объекты jQuery упорядочивают свои элементы в порядке DOM.
1

Использовать этот:

$('#div1, #div2, #div3').each(function(index){
    $(this).delay(1000 * index).hide(1000);
});

Если вы можете дать<div>класс:

$('.forHide').each(function(index, value){
    $(this).delay(1000 * index).hide(1000);
});​
The first element fades out after 1000 * 0 = right away with animation of one second. The second element fades out after 1000 * 1 = One second with animation of one second. The third element fades out after 1000 * 2 = Two seconds with animation of one second. ... ... The n element fades in after 1000 * n = n seconds with animation of one second.

Live DEMO

@Endophage. Они исчезнут в том порядке, в котором они находятся в DOM. взглянуть наthis fiddle
@ gdordon, так что, если вы хотите, чтобы они исчезали в порядке, отличном от того, что есть в dom, скажем, снизу вверх, а не сверху вниз, не существует ли чистого способа сделать это?
Гарантирует ли селектор jquery, что порядок возврата будет тем порядком, который вы поместили в селектор? Просто любопытно...
@Starx. это гарантировано сейчас. проверить это.
Но это не может гарантировать, что эффект завершится через 1000 миллисекунд.
4

Я делаю так, что с помощью этого метода вы можете поместить все элементы 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')});

демонстрация

но после операции с синхронизацией вы будете выполнять две операции синхронно, но если вы установите следующую операцию sync: false, это будет игнорироваться, и вы продолжите выбрасывать следующие две операции, если вы добавите еще одну команду синхронизации, тогда будет 3 операции за один раз и продолжать
Опция синхронизации требует правильного определения синхронных операций и асинхронных операций. таким образом.css() являетсяsync: true и все анимации нет. Кроме этого, я не уверен, что такое "ошибка". Вы говорите о. Если бы это был рабочий код, он мог бы иметь список всех известных методов анимации и определять их автоматически, но я не думал, что в моем ответе уместно подходить. Кроме того, почему вы указали это в качестве комментария к своему ответу, а не к моему (из-за этого я почти не видел ваш комментарий)?
Упс, прочитайте еще одну вещь, xD, я понял, что вы использовали это для метода css, только то, что я неправильно понял мысль, извините. Но я бы не использовал css var, anf, если бы метод не являлся эффектом jquery, я бы обнаружил это и сделал его синхронизированным, только чтобы программист не смог использовать syn var. Но извините за то, что у вас была ошибка.
Вы, кажется, не понимаете, чтоsync используется для. Он используется только для операций, которые выполняются сразу же, как.css() команда, у которой нет функции завершения. При использовании для этих типов операций это не вызывает проблем, которые вы описываете, и работает отлично. Смотрите мой jsFiddle, в котором есть пример того, что не вызывает проблем, которые вы описываете. Вы могли бы иметь десятьsync Операции подряд и до тех пор, пока они на самом деле являются синхронными операциями (вещи, которые выполняются немедленно), это будет работать нормально. Не ставьте синхронизацию на анимацию.
@ jfriend00 в вашем коде есть ошибка с опцией синхронизации, в тот момент, когда у элемента есть синхронизация, вы выбросите еще одну последовательность за раз, я приведу вам пример, чтобы понять ееlist = [0->sync, 1->nosync, 2->sync, 3->nosync, 4->nosync, 5->nosync, 6->nosync, 7->sync]  это будет работать0 1 (because 0 has sync) // 2 (throwed by 0), 3 (throwed by 1), 4 (because o2 has sync) // 5 (throwed by 2), 6 (throwed by 3), 7 (throwed by 4)  и я предположил, что правильный пробег будет0 1 // 2 3 // 4 // 5 // 6 // 7
22

Если вы используете последнюю версию jQuery, используйте обещания анимации:

$('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. Однако это намного более естественно и намного более гибко, если использовать отложенные / обещания, поскольку вы избегаете обратных вызовов «начало».

Просто и чисто - очень красиво :)
pipe () устарела в пользу then () сейчас -
Это оно! Спасибо! Yuval Karmi
Прекрасный код. :)
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/

1

Обратный звонок - это друг, не отталкивай его. Есть способы их упростить. Вот один из них

$('div1').fadeOut('slow', div2)
function div3() { $('div3').fadeOut('slow'); }
function div2() { $('div2').fadeOut('slow', div3); }
1

попробуйте что-то вроде:

$( 'div1' ).fadeOut();
$( 'div2' ).delay( 500  ).fadeOut();
$( 'div3' ).delay( 1000 ).fadeOut();

Отрегулируйте время при необходимости

Это похоже на очень неуклюжий способ сделать это. Кроме того, я полагаю, что задержка не гарантирует согласованности этих событий, особенно при построении цепочки из многих событий.
Он получил 10 элементов. вместо того, чтобы писать это 10 раз, вы можете сделать это с$(...).each и используйте индекс для задержки.check this out
@Brad - На самом деле с JQuery это так. jПри использовании временного интервала между последним и текущим кадрами, поэтому, если браузер не заблокируется, они будут отключены только на несколько мс.

Похожие вопросы