Официальный способ попросить jQuery дождаться загрузки всех изображений перед выполнением чего-либо

641

В jQuery, когда вы делаете это:

$(function() {
   alert("DOM is loaded, but images not necessarily all loaded");
});

Он ожидает загрузки DOM и выполняет ваш код. Если все изображения не загружены, он все равно выполняет код. Это, очевидно, то, что мы хотим, если мы инициализируем какие-либо вещи DOM, такие как показ или скрытие элементов или присоединение событий.

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

Лучший способ - использовать <body onload="finished()">, но я не хочу этого делать, если не буду этого делать.

Примечание: в jQuery 1.3.1 есть ошибка в Internet Explorer, которая действительно ожидает загрузки всех изображений перед выполнением кода внутри $function() { }. Поэтому, если вы используете эту платформу, вы получите поведение, которое я ищу, а не правильное поведение, описанное выше.

Simon_Weaver
источник
3
не $("img").load()работает?
Лукас
1
Я думаю, что стоит упомянуть, что если вы установите атрибуты измерений, вы можете безопасно выполнить некоторый код в готовой функции, которая полагается на эти измерения. С помощью php вы можете получить их с помощью php.net/manual/en/function.getimagesize.php при загрузке, чтобы сохранить их в БД или перед выводом в браузер.
Алкин
если вы хотите, чтобы что-то выполняло невероятную работу, то ознакомьтесь с чрезвычайно хорошей и популярной библиотекой javascript с изображениями, упомянутой в этом ответе ниже stackoverflow.com/a/26458347/759452
Adrien Be
«Здесь я пришел, чтобы найти что-нибудь, кроме официального пути».
Леон Пеллетье

Ответы:

1035

В jQuery вы используете $(document).ready()для выполнения чего-либо, когда загружается DOM, и $(window).on("load", handler)для выполнения чего-либо, когда загружаются также и все остальные объекты, например изображения.

Разницу можно увидеть в следующем полном файле HTML, если у вас есть jollyrogerфайлы JPEG (или другие подходящие):

<html>
    <head>
        <script src="jquery-1.7.1.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                alert ("done");
            });
        </script>
    </head><body>
        Hello
        <img src="jollyroger00.jpg">
        <img src="jollyroger01.jpg">
        // : 100 copies of this
        <img src="jollyroger99.jpg">
    </body>
</html>

При этом окно предупреждения появляется перед загрузкой изображений, потому что DOM готов к этому моменту. Если вы затем измените:

$(document).ready(function() {

в:

$(window).on("load", function() {

то окно предупреждения не появляется до тех пор , после того, как будут загружены изображения.

Следовательно, чтобы подождать, пока вся страница не будет готова, вы можете использовать что-то вроде:

$(window).on("load", function() {
    // weave your magic here.
});
paxdiablo
источник
32
пахнет лбом +1 полностью забыл это. $ (window) .load () не будет срабатывать, пока изображения не будут созданы.
Паоло Бергантино
10
Я сделал то же самое. Даже, прочитайте ответ, не зная, что это был я и все еще не понимая этого.
Римиан
24
Просто примечание - похоже, это не работает под Chromium (и я полагаю, Chrome). Кажется, что событие $ (window) .ready запускается так же, как и $ (document) .ready - до завершения изображений.
Натан Крауз
24
но это $ (window) .load (function ())
TJ-
3
@KyorCode Вы уверены, что это не только потому, что изображения в IE были кэшированы? Если это произойдет, они вообще не будут запускать событие «загрузки». Эта статья помогает обойти эту проблему.
Джейми Баркер
157

Я написал плагин, который может запускать обратные вызовы, когда изображения загружаются в элементы, или запускаться один раз для каждого загруженного изображения.

Это похоже на $(window).load(function() { .. }), за исключением того, что позволяет определить любой селектор для проверки. Если вы хотите знать, когда все изображения в #content(например) загружены, это плагин для вас.

Он также поддерживает загрузку изображений , упоминаемых в CSS, такие как background-image, list-style-imageи т.д.

waitForImages плагин jQuery

Пример использования

$('selector').waitForImages(function() {
    alert('All images are loaded.');
});

Пример на jsFiddle .

Больше документации доступно на странице GitHub.

Алекс
источник
1
Спасибо!! $ .load () не работал для меня, но это отлично работает.
Fraxtil
Я использую Chrome версии 22.0.1229.94 и этот плагин, и я попытался прочитать смещения из загруженных изображений в waitFormImages: ('img selector').each(function(index) { var offset = $(this).offset(); ...});однако, offset.top по-прежнему равен нулю. Почему?
BasZero
1
@basZero Трудно сказать без контекста. Пожалуйста, поднимите вопрос на странице Проблемы .
Алекс
Это не работает для меня, когда изображения связаны. У кого-нибудь есть обходной путь для этого?
Мэндип Джайн
2
Он в основном аналогичен imagesLoaded, но работает и с srcsets. Именно то, что я искал! Отличный плагин!
Фабиан Шенер
48

$(window).load()будет работать только при первой загрузке страницы. Если вы делаете динамические вещи (например: нажмите кнопку, подождите, пока загрузятся новые изображения), это не сработает. Для этого вы можете использовать мой плагин:

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

Скачать

/**
 *  Plugin which is applied on a list of img objects and calls
 *  the specified callback function, only when all of them are loaded (or errored).
 *  @author:  H. Yankov (hristo.yankov at gmail dot com)
 *  @version: 1.0.0 (Feb/22/2010)
 *  http://yankov.us
 */

(function($) {
$.fn.batchImageLoad = function(options) {
    var images = $(this);
    var originalTotalImagesCount = images.size();
    var totalImagesCount = originalTotalImagesCount;
    var elementsLoaded = 0;

    // Init
    $.fn.batchImageLoad.defaults = {
        loadingCompleteCallback: null, 
        imageLoadedCallback: null
    }
    var opts = $.extend({}, $.fn.batchImageLoad.defaults, options);

    // Start
    images.each(function() {
        // The image has already been loaded (cached)
        if ($(this)[0].complete) {
            totalImagesCount--;
            if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
        // The image is loading, so attach the listener
        } else {
            $(this).load(function() {
                elementsLoaded++;

                if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);

                // An image has been loaded
                if (elementsLoaded >= totalImagesCount)
                    if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
            });
            $(this).error(function() {
                elementsLoaded++;

                if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);

                // The image has errored
                if (elementsLoaded >= totalImagesCount)
                    if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
            });
        }
    });

    // There are no unloaded images
    if (totalImagesCount <= 0)
        if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
};
})(jQuery);
Roko C. Buljan
источник
на всякий случай кому-нибудь понадобится пример использования плагина BatchImagesLoad
Джонатан Марзулло
1
Я имею в виду неуважение, но нельзя полагаться "просто" на ваше слово в отношении надежности вашего плагина. Как уже упоминалось в Yevgeniy Afanasyevответе , imagesLoaded справляется с этой задачей гораздо лучше и охватывает сценарий использования, который вы упомянули, наряду со многими другими примерами (см. Решенные проблемы с github) .
Adrien Be
19

Для тех, кто хочет получать уведомления о завершении загрузки одного изображения, которое запрашивается после $(window).loadпожара, вы можете использовать loadсобытие элемента изображения .

например:

// create a dialog box with an embedded image
var $dialog = $("<div><img src='" + img_url + "' /></div>");

// get the image element (as a jQuery object)
var $imgElement = $dialog.find("img");

// wait for the image to load 
$imgElement.load(function() {
    alert("The image has loaded; width: " + $imgElement.width() + "px");
});
Дан Пассаро
источник
13

Ни один из ответов до сих пор не дал того, что кажется самым простым решением.

$('#image_id').load(
  function () {
    //code here
});
Коз
источник
Что хорошо в этом, так это то, что вы можете заставить его запускаться для отдельных изображений, как только они загружаются.
Top Cat
6

Я бы порекомендовал использовать imagesLoaded.jsбиблиотеку JavaScript.

Почему бы не использовать JQuery $(window).load()?

Как указано на /programming/26927575/why-use-imagesloaded-javascript-library-versus-jquerys-window-load/26929951

Это вопрос сферы. imagesLoaded позволяет вам нацеливать набор изображений, тогда как $(window).load()нацеливается на все ресурсы - включая все изображения, объекты, файлы .js и .css и даже iframes. Скорее всего, imagesLoaded будет срабатывать раньше, чем $(window).load()потому, что он нацелен на меньший набор ресурсов.

Другие веские причины использовать загруженные изображения

  • официально поддерживается IE8 +
  • лицензия: лицензия MIT
  • зависимости: нет
  • вес (минимизированный и сжатый): 7 КБ минимизированный (легкий!)
  • скачать конструктор (помогает снизить вес): не нужно, уже крошечный
  • на Github: ДА
  • сообщество и участники: довольно большое, 4000+ участников, хотя всего 13 участников
  • история и вклады: стабильный как относительно старый (с 2010 года), но все еще активный проект

Ресурсы

Адриен Бе
источник
4

С JQuery я иду с этим ...

$(function() {
    var $img = $('img'),
        totalImg = $img.length;

    var waitImgDone = function() {
        totalImg--;
        if (!totalImg) alert("Images loaded!");
    };

    $('img').each(function() {
        $(this)
            .load(waitImgDone)
            .error(waitImgDone);
    });
});

Демо: http://jsfiddle.net/molokoloco/NWjDb/

molokoloco
источник
Я обнаружил, что это не будет работать должным образом, если браузер возвращает 304 Not Mofified ответ для изображения, означающий, что изображение кэшируется.
JohnyFree
1

Используйте imagesLoaded PACKAGED v3.1.8 (6,8 Кбайт, когда свернуты). Это относительно старый (с 2010 года), но все еще активный проект.

Вы можете найти его на github: https://github.com/desandro/imagesloaded

Их официальный сайт: http://imagesloaded.desandro.com/

Почему это лучше, чем использовать:

$(window).load() 

Потому что вы можете загружать изображения динамически, например так: jsfiddle

$('#button').click(function(){
    $('#image').attr('src', '...');
});
Евгений Афанасьев
источник
1
На самом деле загруженные изображения не поддерживают изменение значения атрибута src в разных браузерах. Вы должны каждый раз создавать новый элемент изображения. Попробуйте это на Firefox, и вы увидите, что проблема появляется.
Адриен Бе
Хороший вопрос, я только тестировал на Google Chrome и IE-11. Это работало. Спасибо.
Евгений Афанасьев
Я добавил эту проблему с несколькими браузерами в свой вопрос stackoverflow.com/q/26927575 в пункте «Что вы не можете делать с загруженными изображениями», см. Соответствующую проблему imagesLoaded на Github github.com/desandro/imagesloaded/issues/121
Adrien Быть
1

Таким образом, вы можете выполнить действие, когда все изображения внутри тела или любого другого контейнера (в зависимости от вашего выбора) загружены. PURE JQUERY, никаких плагинов не требуется.

var counter = 0;
var size = $('img').length;

$("img").load(function() { // many or just one image(w) inside body or any other container
    counter += 1;
    counter === size && $('body').css('background-color', '#fffaaa'); // any action
}).each(function() {
  this.complete && $(this).load();        
});
Марио Медрано
источник
0

Мое решение похоже на молоколоко . Написано как функция jQuery:

$.fn.waitForImages = function (callback) {
    var $img = $('img', this),
        totalImg = $img.length;

    var waitImgLoad = function () {
        totalImg--;
        if (!totalImg) {
            callback();
        }
    };

    $img.each(function () {
        if (this.complete) { 
            waitImgLoad();
        }
    })

    $img.load(waitImgLoad)
        .error(waitImgLoad);
};

пример:

<div>
    <img src="img1.png"/>
    <img src="img2.png"/>
</div>
<script>
    $('div').waitForImages(function () {
        console.log('img loaded');
    });
</script>
Мариуш Чарчук
источник