Как предотвратить jQuery-код от слишком много функций вложенности?

17

Я не знаю, правильно ли вызывается этот nesting ? Но я знаю, что это не хороший код, чтобы иметь много функций внутри друг друга. Большинство методов jQuery имеют функцию обратного вызова, в которой мы можем поместить наши обратные вызовы. Но когда мы выполняем обратные вызовы внутри другого обратного вызова и продолжаем это и все глубже и глубже, кажется, что код становится менее читаемым и, возможно, менее отлаживаемым.

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

$('#t').animate({height: 400}, 500, function(){
    $(this).animate({height: 200}, 500, function(){
        $(this).animate({width: 300}, 500, function(){
            $(this).animate({height: 300}, 500, function(){
                $(this).animate({'border-radius': '50px'}, 500, function(){
                    //and so on...
                });
            });
        });
    });
});

для выполнения 5-ступенчатой ​​анимации мне нужно сделать 5-уровневый стек вызовов. Итак, мой вопрос в том, как вы избегаете этого? У меня была такая же проблема и в моих Node.js-функциях.

Update: Я знаю, что функция jQuery имеет функцию chinning, но это не решает проблему. потому что вы не можете сделать что-то среднее между цепочкой. Вы можете написать выше код, например $(selector').animate().animate()... , но вы не можете сделать то же самое для этого:

$('#t').animate({height: 400}, 500, function(){
        console.log('step 1 done: like a boss');
        $(this).animate({height: 200}, 500, function(){
            console.log('step 2 done: like a boss');
            $(this).animate({width: 300}, 500, function(){
                console.log('step 3 done: like a boss');
                $(this).animate({height: 300}, 500, function(){
                    console.log('step 4 done: like a boss');
                    $(this).animate({'border-radius': '50px'}, 500, function(){
                        //and so on...
                    });
                });
            });
        });
    });

Идеальным решением будет такой код:

$(selector).doQ(anim1, anim2, myfunc1, anim3, myfunc2)...

Но, к сожалению, у jQuery нет такого API (насколько мне известно).

    
задан Mohsen 18.09.2011 в 23:45
источник
  • Я не думаю, что есть проблема с такими функциями вложенности. –  Nathan 18.09.2011 в 23:49
  • @ Натан: Действительно? Попробуйте отладить, сохранить и прочитать код, который глубоко вложен. –  Andrew Whitaker 18.09.2011 в 23:54
  • @ Андрю Я имею в виду, я думаю, что это сработает. Я думал, что он спрашивает, правильно это или нет. И да, очень сложно отлаживать, читать и поддерживать. –  Nathan 19.09.2011 в 00:00
  • jCeption. Мы должны откликнуться глубже ... Хорошо, я закончил. –  Bojangles 19.09.2011 в 00:18

6 ответов

23
  

* "Идеальным решением будет такой код:

     

$ (селектор) .doQ (anim1, anim2, myfunc1, anim3, myfunc2) ... "*

Это не совсем то, что вы хотите, но у jQuery есть queue() [docs] :

$(selector).animate({height: 400}, 500)
           .animate({height: 200}, 500)
           .queue( myfunc1 )
           .animate({width: 300}, 500)
           .queue( myfunc2 );

Вам просто нужно убедиться, что ваши функции освободят очередь, когда они будут выполнены, используя dequeue() [docs] :

function myfunc1() {
    // your code
    $(this).dequeue();
}

Или вы можете обернуть свои функции в анонимную функцию и вызвать там dequeue:

$(selector).animate({height: 400}, 500)
           .animate({height: 200}, 500)
           .queue( function( nxt ) {
               myfunc1();
               $(this).dequeue();
            })
           .animate({width: 300}, 500)
           .queue( function( nxt ) {
               myfunc2();
               nxt(); // alternate way to dequeue
            });
    
ответ дан user113716 19.09.2011 в 00:20
источник
  • , но myfunc1 должен принять следующий аргумент и запустить next (); когда это будет сделано, или оно не будет продолжаться. –  evan 19.09.2011 в 00:23
  • Ха, я просто написал это тоже;) +1 –  Felix Kling 19.09.2011 в 00:24
  • @evan: см. мои обновления, хотя вы можете использовать .dequeue () вместо переданного аргумента. –  user113716 19.09.2011 в 00:25
  • @patrick, как всегда ваш ответ является совершенным, подробным и удивительным! благодаря –  Mohsen 19.09.2011 в 00:31
  • Добро пожаловать @Moshen. :) –  user113716 19.09.2011 в 00:35
7

Прочитайте очереди jQuery. Ваш код также может быть написан следующим образом:

$('#t')
    .animate({height: 400}, 500)
    .animate({height: 200}, 500)
    .animate({width: 300}, 500)
    .animate({height: 300}, 500)
    .animate({'border-radius': '50px'}, 500);

Первая анимация запускается немедленно, а остальные помещаются в очередь «fx» и исполняются по очереди, когда остальные заканчиваются.     

ответ дан Matt Bradley 18.09.2011 в 23:51
источник
  • Я обновил свой вопрос. Взглянуть. Я знаю, как работает цепочка ... –  Mohsen 19.09.2011 в 00:02
  • @Mohsen Вы можете комбинировать подход цепочки и обратные вызовы ... –  lonesomeday 19.09.2011 в 00:05
  • , поэтому мой вопрос КАК ?! :) –  Mohsen 19.09.2011 в 00:07
  • $ ('# t'). animate ({height: 400}, 500, function () {/ * ... * /}). animate ({height: 200}, 500, function () {/ * ... * /}); и т.д –  evan 19.09.2011 в 00:12
4

Читайте в отложенном объекте JQuery

  

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

Если ваши обратные вызовы являются ТОЛЬКО анимацией, тогда просто соедините их и используйте очередь fx JQuery.

    
ответ дан AlienWebguy 18.09.2011 в 23:51
источник
  • Мой вопрос касается ситуации, когда нет обратного звонка ... –  Mohsen 19.09.2011 в 00:06
4

Объекты jQuery имеют очередь по умолчанию. Попробуйте эту скрипту: Ссылка

    
ответ дан gislikonrad 18.09.2011 в 23:52
источник
  • Что делать, если вы хотите что-то сделать между ними? Посмотрите мой обновленный вопрос –  Mohsen 18.09.2011 в 23:55
  • Это никогда не было частью вопроса ... Однако вы могли бы связать анимацию, иметь обратный вызов, когда хотите сделать что-то дополнительное, а затем завершить цепочку в обратном вызове. –  gislikonrad 19.09.2011 в 00:00
2

Немного более чистый способ:

$('#t')
    .animate({height: 400}, 500, animationDone)
    .animate({height: 200}, 500, animationDone)
    .animate({width : 200}, 500, animationDone)
    .animate({height: 300}, 500, animationDone)
    .animate({'border-radius': '50px'}, 500, animationDone);


var logCount = 0;
function animationDone(e) {
    logCount++;

    $("#t").html("Animation # " + logCount + " has completed!");
}

Просто сделайте что-нибудь, основанное на logCount . Пример можно увидеть здесь .

    
ответ дан Shaz 19.09.2011 в 00:42
источник
  • Спасибо за ответ. Я не хотел решения на основе случая. Я просто добавлю пример для лучшего понимания вопроса –  Mohsen 19.09.2011 в 01:28
0

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

  var clicka = function(){
    alert("I got clicked after t.")
  }
  var clickt = function(){
        alert("I got clicked!")
        $('#a').click(clicka)
  }
  $('#t').click(clickt);
    
ответ дан bigblind 18.09.2011 в 23:50
источник