Заметки за август 2009 года

Событие окончания загрузки картинки

Чтобы отследить момент загрузки картинки одного обработчика события «load» бывает не достаточно. Если он будет прикреплен к картинке после того, как она уже была загружена, то событие больше не повторится и обработчик не будет вызван.

Поможет решить эту проблему вспомогательный плагин к jQuery.

;(function ($) {
    $.fn.bindImageLoad = function (callback) {
        function isImageLoaded(img) {
            // Во время события load IE и другие браузеры правильно
            // определяют состояние картинки через атрибут complete.
            // Исключение составляют Gecko-based браузеры.
            if (!img.complete) {
                return false;
            }
            // Тем не менее, у них есть два очень полезных свойства: naturalWidth и naturalHeight.
            // Они дают истинный размер изображения. Если какртинка еще не загрузилась,
            // то они должны быть равны нулю.
            if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
                return false;
            }
            // Картинка загружена.
            return true;
        }

        return this.each(function () {
            var ele = $(this);
            if (ele.is("img") && $.isFunction(callback)) {
                ele.one("load", callback);
                if (isImageLoaded(this)) {
                    ele.trigger("load");
                }
            }
        });
    };
})(jQuery);

Обновление: Работу плагина можно посмотреть в примере. Там используется немного модифицированная версия, которая формирует специальное событие.

Комментарии к заметке: 31

Очереди в jQuery

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

В jQuery тоже есть механизм, реализующий очередь — это функции queue и dequeue.

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

Рассмотрим пример:

$("#result")
    .queue("test", function () {
        $(this)
            .append("<p>1st function</p>")
            .queue("test", function () {
                $(this)
                    .append("<p>4th function</p>")
                    .dequeue("test");
            })
            .dequeue("test");
    })
    .queue("test", function () {
        $(this)
            .append("<p>2nd function</p>")
            .dequeue("test");
    })
    .queue("test", function () {
        $(this)
            .append("<p>3rd function. " +
                    $(this).queue("test").length +
                    " function(s) in queue</p>")
            .queue("test", function () {
                $(this)
                    .append("<p>5th function</p>")
                    .dequeue("test");
            })
            .dequeue("test");
    })
    .dequeue("test");

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

Результатом работы этого кода будет:

1st function
2nd function
3rd function. 1 function(s) in queue
4th function
5th function

В третьей по счету функции выводится количество оставшихся функций в очереди. На момент исполнения там остается только одна функция (4-ая по счету), но сразу после этого добавляется еще и 5-ая.

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

Комментарии к заметке: 3