Какие очереди в jQuery?

387

Я нашел документ jQuery.com на queue()/ dequeue()слишком прост для понимания. Что такое очереди в jQuery? Как я должен их использовать?

jquerynewbie
источник
3
Хороший пример решения проблемы с очередью: stackoverflow.com/questions/5230333/…
gnarf

Ответы:

488

Использование jQuery .queue()и.dequeue()

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

Чтобы понять внутренние функции очереди jQuery, мне очень помогает чтение исходного кода и просмотр примеров. Один из лучших примеров функции очереди, которую я видел .delay():

$.fn.delay = function( time, type ) {
  time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
  type = type || "fx";

  return this.queue( type, function() {
    var elem = this;
    setTimeout(function() {
      jQuery.dequeue( elem, type );
    }, time );
  });
};

Очередь по умолчанию - fx

Очередь по умолчанию в jQuery fx. Очередь по умолчанию имеет некоторые специальные свойства, которые не используются совместно с другими очередями.

  1. Автоматический запуск: При вызове $(elem).queue(function(){});в fxочереди будет автоматически dequeueследующая функция и запустить его , если очередь не началась.
  2. 'inprogress' sentinel: всякий раз, когда вы dequeue()выполняете функцию из fxочереди, она unshift()(помещает в первое место массива) строку "inprogress"- которая указывает, что очередь в данный момент выполняется.
  3. Это по умолчанию! fxОчередь используется , .animate()и все функции , которые называют его по умолчанию.

ПРИМЕЧАНИЕ. Если вы используете пользовательскую очередь, вы должны вручную включить .dequeue()функции, они не запустятся автоматически!

Получение / Установка очереди

Вы можете получить ссылку на очередь jQuery, вызвав ее .queue()без аргумента функции. Вы можете использовать метод, если вы хотите увидеть, сколько элементов в очереди. Вы можете использовать push, pop, unshift, shiftуправлять очередью на месте. Вы можете заменить всю очередь, передав массив .queue()функции.

Быстрые примеры:

// lets assume $elem is a jQuery object that points to some element we are animating.
var queue = $elem.queue();
// remove the last function from the animation queue.
var lastFunc = queue.pop(); 
// insert it at the beginning:    
queue.unshift(lastFunc);
// replace queue with the first three items in the queue
$elem.queue(queue.slice(0,3)); 

Пример fxочереди анимации ( ):

Пример запуска на jsFiddle

$(function() {
    // lets do something with google maps:
    var $map = $("#map_canvas");
    var myLatlng = new google.maps.LatLng(-34.397, 150.644);
    var myOptions = {zoom: 8, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP};
    var geocoder = new google.maps.Geocoder();
    var map = new google.maps.Map($map[0], myOptions);
    var resized = function() {
        // simple animation callback - let maps know we resized
        google.maps.event.trigger(map, 'resize');
    };

    // wait 2 seconds
    $map.delay(2000);
    // resize the div:
    $map.animate({
        width: 250,
        height: 250,
        marginLeft: 250,
        marginTop:250
    }, resized);
    // geocode something
    $map.queue(function(next) {
        // find stackoverflow's whois address:
      geocoder.geocode({'address': '55 Broadway New York NY 10006'},handleResponse);

      function handleResponse(results, status) {
          if (status == google.maps.GeocoderStatus.OK) {
              var location = results[0].geometry.location;
              map.setZoom(13);
              map.setCenter(location);
              new google.maps.Marker({ map: map, position: location });
          }
          // geocoder result returned, continue with animations:
          next();
      }
    });
    // after we find stack overflow, wait 3 more seconds
    $map.delay(3000);
    // and resize the map again
    $map.animate({
        width: 500,
        height: 500,
        marginLeft:0,
        marginTop: 0
    }, resized);
});

Другой пример пользовательской очереди

Пример запуска на jsFiddle

var theQueue = $({}); // jQuery on an empty object - a perfect queue holder

$.each([1,2,3],function(i, num) {
  // lets add some really simple functions to a queue:
  theQueue.queue('alerts', function(next) { 
    // show something, and if they hit "yes", run the next function.
    if (confirm('index:'+i+' = '+num+'\nRun the next function?')) {
      next();
    }
  }); 
});

// create a button to run the queue:
$("<button>", {
  text: 'Run Queue', 
  click: function() { 
    theQueue.dequeue('alerts'); 
  }
}).appendTo('body');

// create a button to show the length:
$("<button>", {
  text: 'Show Length', 
  click: function() { 
    alert(theQueue.queue('alerts').length); 
  }
}).appendTo('body');

Очереди Ajax Calls:

Я разработал $.ajaxQueue()плагин , который использует $.Deferred, .queue()и $.ajax()также передать обратно обещание , что не будет решена , если запрос не завершится. Другая версия, $.ajaxQueueкоторая все еще работает в 1.4, опубликована в моем ответе на Sequencing Ajax Requests.

/*
* jQuery.ajaxQueue - A queue for ajax requests
* 
* (c) 2011 Corey Frang
* Dual licensed under the MIT and GPL licenses.
*
* Requires jQuery 1.5+
*/ 
(function($) {

// jQuery on an empty object, we are going to use this as our Queue
var ajaxQueue = $({});

$.ajaxQueue = function( ajaxOpts ) {
    var jqXHR,
        dfd = $.Deferred(),
        promise = dfd.promise();

    // queue our ajax request
    ajaxQueue.queue( doRequest );

    // add the abort method
    promise.abort = function( statusText ) {

        // proxy abort to the jqXHR if it is active
        if ( jqXHR ) {
            return jqXHR.abort( statusText );
        }

        // if there wasn't already a jqXHR we need to remove from queue
        var queue = ajaxQueue.queue(),
            index = $.inArray( doRequest, queue );

        if ( index > -1 ) {
            queue.splice( index, 1 );
        }

        // and then reject the deferred
        dfd.rejectWith( ajaxOpts.context || ajaxOpts,
            [ promise, statusText, "" ] );

        return promise;
    };

    // run the actual query
    function doRequest( next ) {
        jqXHR = $.ajax( ajaxOpts )
            .done( dfd.resolve )
            .fail( dfd.reject )
            .then( next, next );
    }

    return promise;
};

})(jQuery);

Теперь я добавил это как статью на learn.jquery.com , на этом сайте есть и другие замечательные статьи об очередях, посмотрите.

gnarf
источник
+1. Я работаю над пользовательским сценарием на основе jQuery, который должен подключаться к сценарию PHP, как если бы это был другой сценарий PHP, выполняющийся на клиенте - по одному HTTP-запросу / другой операции за раз, поэтому это, безусловно, будет полезно. Просто вопрос: jQuery требует, чтобы очереди были прикреплены к объектам, верно? Так какой объект я должен использовать? $(window)?
Пожалуйста, установите
3
@idealmachine - Как видно из примера очереди Ajax, вы можете прикрепить события очереди к пустому объекту:$({})
gnarf
3
Это резюме невероятно полезно. Я только что закончил сборку ленивого загрузчика для задержки запроса на тяжелый контент, который находится ниже нижней части экрана, пока он не будет прокручен. Использование jQuery queue () сделало эти запросы Ajax очень плавными (даже если вы прыгаете прямо в конец страницы). Спасибо!
Джефф Стэнден
14
Приятно узнать, что вы все еще обновляете это для новых версий jQuery. +1 :)
Шаз
3
Чтобы добавить одну вещь для тех, кто только изучает очереди и обещания и т. Д. - в примере ajaxQueue вызов $ .ajaxQueue (), в который вы помещаете запрос ajax, который вы хотите поместить в очередь внутри (), возвращает обещание. Вы ожидаете, пока очередь не опустеет, - через обещание.done (function () {alert ("done")}) ;. Мне понадобился час, чтобы найти это, так что надеюсь, что это поможет кому-то еще спасти свой час!
Росс
42

Чтобы понять метод очереди, вы должны понимать, как jQuery выполняет анимацию. Если вы пишете несколько вызовов метода animate один за другим, jQuery создает «внутреннюю» очередь и добавляет к ней эти вызовы метода. Затем он запускает эти одушевленные звонки один за другим.

Рассмотрим следующий код.

function nonStopAnimation()
{
    //These multiple animate calls are queued to run one after
    //the other by jQuery.
    //This is the reason that nonStopAnimation method will return immeidately
    //after queuing these calls. 
    $('#box').animate({ left: '+=500'}, 4000);
    $('#box').animate({ top: '+=500'}, 4000);
    $('#box').animate({ left: '-=500'}, 4000);

    //By calling the same function at the end of last animation, we can
    //create non stop animation. 
    $('#box').animate({ top: '-=500'}, 4000 , nonStopAnimation);
}

Метод 'queue' / 'dequeue' дает вам контроль над этой 'очередью анимации'.

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

http://jsbin.com/zoluge/1/edit?html,output

Код для вышеприведенного примера страницы:

$(document).ready(function() {
    $('#nonStopAnimation').click(nonStopAnimation);

    $('#stopAnimationQueue').click(function() {
        //By default all animation for particular 'selector'
        //are queued in queue named 'fx'.
        //By clearning that queue, you can stop the animation.
        $('#box').queue('fx', []);
    });

    $('#addAnimation').click(function() {
        $('#box').queue(function() {
            $(this).animate({ height : '-=25'}, 2000);
            //De-queue our newly queued function so that queues
            //can keep running.
            $(this).dequeue();
        });
    });

    $('#stopAnimation').click(function() {
        $('#box').stop();
    });

    setInterval(function() {
        $('#currentQueueLength').html(
         'Current Animation Queue Length for #box ' + 
          $('#box').queue('fx').length
        );
    }, 2000);
});

function nonStopAnimation()
{
    //These multiple animate calls are queued to run one after
    //the other by jQuery.
    $('#box').animate({ left: '+=500'}, 4000);
    $('#box').animate({ top: '+=500'}, 4000);
    $('#box').animate({ left: '-=500'}, 4000);
    $('#box').animate({ top: '-=500'}, 4000, nonStopAnimation);
}

Теперь вы можете спросить, почему я должен беспокоиться об этой очереди? Обычно вы этого не сделаете. Но если у вас есть сложная анимационная последовательность, которой вы хотите управлять, то методы очереди / очереди - ваш друг.

Также посмотрите этот интересный разговор в группе jQuery о создании сложной анимационной последовательности.

http://groups.google.com/group/jquery-en/browse_thread/thread/b398ad505a9b0512/f4f3e841eab5f5a2?lnk=gst

Демо анимации:

http://www.exfer.net/test/jquery/tabslide/

Дайте мне знать, если у вас все еще есть вопросы.

SolutionYogi
источник
20

Анимация нескольких объектов в очереди

Вот простой пример анимации нескольких объектов в очереди.

Jquery позволяет нам ставить в очередь только один объект. Но внутри функции анимации мы можем получить доступ к другим объектам. В этом примере мы строим нашу очередь поверх объекта #q, анимируя объекты # box1 и # box2.

Думайте об очереди как о массиве функций. Таким образом, вы можете управлять очередью как массивом. Вы можете использовать push, pop, unshift, shift для управления очередью. В этом примере мы удаляем последнюю функцию из очереди анимации и вставляем ее в начале.

Когда мы закончим, мы запускаем очередь анимации с помощью функции dequeue ().

Смотрите на jsFiddle

HTML:

  <button id="show">Start Animation Queue</button>
  <p></p>
  <div id="box1"></div>
  <div id="box2"></div>
  <div id="q"></div>

ЯШ:

$(function(){

 $('#q').queue('chain',function(next){  
      $("#box2").show("slow", next);
  });


  $('#q').queue('chain',function(next){  
      $('#box1').animate(
          {left: 60}, {duration:1000, queue:false, complete: next}
      )
  });    


  $('#q').queue('chain',function(next){  
      $("#box1").animate({top:'200'},1500, next);
  });


  $('#q').queue('chain',function(next){  
      $("#box2").animate({top:'200'},1500, next);
  });


  $('#q').queue('chain',function(next){  
      $("#box2").animate({left:'200'},1500, next);
  });

  //notice that show effect comes last
  $('#q').queue('chain',function(next){  
      $("#box1").show("slow", next);
  });

});

$("#show").click(function () {
    $("p").text("Queue length is: " + $('#q').queue("chain").length);

    // remove the last function from the animation queue.
    var lastFunc = $('#q').queue("chain").pop();
    // insert it at the beginning:    
    $('#q').queue("chain").unshift(lastFunc);

    //start animation queue
    $('#q').dequeue('chain');
});

CSS:

        #box1 { margin:3px; width:40px; height:40px;
                position:absolute; left:10px; top:60px; 
                background:green; display: none; }
        #box2 { margin:3px; width:40px; height:40px;
                position:absolute; left:100px; top:60px; 
                background:red; display: none; }
        p { color:red; }  
enf644
источник
15

Это позволяет вам ставить в очередь анимации ... например, вместо этого

$('#my-element').animate( { opacity: 0.2, width: '100px' }, 2000);

Который затемняет элемент и делает ширину 100 пикселей одновременно . Использование очереди позволяет ставить анимацию. Итак, одно заканчивается за другим.

$("#show").click(function () {
    var n = $("div").queue("fx");
    $("span").text("Queue length is: " + n.length);
});

function runIt() {
    $("div").show("slow");
    $("div").animate({left:'+=200'},2000);
    $("div").slideToggle(1000);
    $("div").slideToggle("fast");
    $("div").animate({left:'-=200'},1500);
    $("div").hide("slow");
    $("div").show(1200);
    $("div").slideUp("normal", runIt);
}
runIt();

Пример из http://docs.jquery.com/Effects/queue

alex
источник
Это не правильно. Когда у вас есть несколько «одушевленных» вызовов, jQuery помещает их в очередь, чтобы выполнить их один за другим. Используя метод очереди, теперь вы можете получить доступ к этой очереди и манипулировать ею, если это необходимо.
SolutionYogi
1
@SolutionYogi - Пожалуйста, отредактируйте мой ответ, если считаете, что он неправильный - ответ CW'd, и у вас достаточно повторений.
Алекс
8

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

/* create an empty queue */
var theQueue = $({});
/* loop through the data array */
for (var i = 0; i < ph.length; i++) {
    for (var l = 0; l < ph[i].length; l++) {
        /* create a function which swaps an image, and calls the next function in the queue */
        theQueue.queue("anim", new Function("cb", "$('ph_"+i+"' img').attr('src', '/images/"+i+"/"+l+".png');cb();"));
        /* set the animation speed */
        theQueue.delay(200,'anim');
    }
}
/* start the animation */
theQueue.dequeue('anim');

Это упрощенная версия скрипта, к которому я пришел, но он должен показать принцип - когда функция добавляется в очередь, она добавляется с помощью конструктора Function - таким образом, функция может быть написана динамически с использованием переменных из цикла ( с). Обратите внимание на способ, которым функции передается аргумент для вызова next (), и это вызывается в конце. Функция в этом случае не имеет временной зависимости (она не использует $ .fadeIn или что-то в этом роде), поэтому я разбиваю кадры с помощью $ .delay.

bjorsq
источник
$ .queue - это, по сути, толчок к массиву, хранящемуся в $ .data, поэтому вы должны вручную указать ему выполнить следующую функцию с помощью cb (); Правильно ли мое понимание?
восемь глаз
-1

Функции makeRedи makeBlackиспользовать queueи dequeueвыполнять друг друга. В результате элемент #wow постоянно мигает.

<html>
  <head>
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript">
      $(document).ready(function(){
          $('#wow').click(function(){
            $(this).delay(200).queue(makeRed);
            });
          });

      function makeRed(){
        $('#wow').css('color', 'red');
        $('#wow').delay(200).queue(makeBlack);
        $('#wow').dequeue();
      }

      function makeBlack(){
        $('#wow').css('color', 'black');
        $('#wow').delay(200).queue(makeRed);
        $('#wow').dequeue();
      }
    </script>
  </head>
  <body>
    <div id="wow"><p>wow</p></div>
  </body>
</html>
ardsrk
источник