Обратный вызов jQuery при загрузке изображения (даже при кэшировании изображения)

Я хочу сделать:

$("img").bind('load', function() {
  // do stuff
});

Но событие загрузки не срабатывает, когда изображение загружается из кеша. Документы jQuery предлагают плагин, чтобы исправить это, но он не работает

Ответ 1

Если src уже установлен, то событие запускается в кэшированном случае еще до того, как вы получите привязку обработчика события. Чтобы это исправить, вы можете пройти проверку и запускать событие на основе .complete, например так:

$("img").one("load", function() {
  // do stuff
}).each(function() {
  if(this.complete) {
      $(this).load(); // For jQuery < 3.0 
      // $(this).trigger('load'); // For jQuery >= 3.0 
  }
});

Обратите внимание на изменение с .bind() на .one() чтобы обработчик событий не запускался дважды.

Ответ 2

Могу ли я предложить перезагрузить его в объект изображения, отличного от DOM? Если он будет сохранен в кэше, это совсем не займет времени, и нагрузка по-прежнему будет срабатывать. Если он не кэшируется, он будет запускать загрузку при загрузке изображения, что должно совпадать с тем, как версия DOM изображения заканчивается загрузкой.

JavaScript:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.src = $('#img').attr('src') ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;
}) ;

Обновлено (для обработки нескольких изображений и с правильно упорядоченным приложением onload):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;

Ответ 3

Мое простое решение, ему не нужен внешний плагин, и для обычных случаев должно быть достаточно:

/**
 * Trigger a callback when the selected images are loaded:
 * @param {String} selector
 * @param {Function} callback
  */
var onImgLoad = function(selector, callback){
    $(selector).each(function(){
        if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
            callback.apply(this);
        }
        else {
            $(this).on('load', function(){
                callback.apply(this);
            });
        }
    });
};

используйте его следующим образом:

onImgLoad('img', function(){
    // do stuff
});

например, для постепенного исчезновения ваших изображений при загрузке:

$('img').hide();
onImgLoad('img', function(){
    $(this).fadeIn(700);
});

Или как альтернатива, если вы предпочитаете подход, похожий на jquery:

/**
 * Trigger a callback when 'this' image is loaded:
 * @param {Function} callback
 */
(function($){
    $.fn.imgLoad = function(callback) {
        return this.each(function() {
            if (callback) {
                if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
                    callback.apply(this);
                }
                else {
                    $(this).on('load', function(){
                        callback.apply(this);
                    });
                }
            }
        });
    };
})(jQuery);

и используйте его таким образом:

$('img').imgLoad(function(){
    // do stuff
});

например:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});

Ответ 4

Вам действительно нужно делать это с помощью jQuery? Вы можете прикрепить событие onload непосредственно к своему изображению,

<img src="/path/to/image.jpg" onload="doStuff(this);" />

Он будет запускаться каждый раз, когда изображение загрузилось, из кеша или нет.

Ответ 5

Вы также можете использовать этот код с поддержкой ошибки загрузки:

$("img").on('load', function() {
  // do stuff on success
})
.on('error', function() {
  // do stuff on smth wrong (error 404, etc.)
})
.each(function() {
    if(this.complete) {
      $(this).load();
    } else if(this.error) {
      $(this).error();
    }
});

Ответ 6

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

Я не видел эту нить сразу, поэтому я нашел что-то другое, а это интересное исправление и (я думаю), достойное публикации здесь:

$('.image').load(function(){
    // stuff
}).attr('src', 'new_src');

Я получил эту идею от комментариев здесь: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

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

Надеюсь, что это поможет,

Изменить

Принятый ответ на самом деле объясняет, почему:

Если src уже установлен, событие запускается в кеш-кеш, прежде чем вы получите привязку обработчика события.

Ответ 7

Решение, которое я нашел https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (Этот код взят непосредственно из комментария)

var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;

Ответ 8

Модификация примера GUS:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;

tmpImg.src = $('#img').attr('src');
})

Установите источник до и после загрузки.

Ответ 9

Используя jQuery для создания нового изображения с изображением src и непосредственного назначения метода загрузки, метод загрузки успешно вызывается, когда jQuery заканчивает создание нового изображения. Это работает для меня в IE 8, 9 и 10

$('<img />', {
    "src": $("#img").attr("src")
}).load(function(){
    // Do something
});

Ответ 10

Просто повторно добавьте аргумент src в отдельной строке после определения img oject. Это приведет к запуску IE в запуске lad-event. Это уродливо, но это самый простой способ, который я нашел до сих пор.

jQuery('<img/>', {
    src: url,
    id: 'whatever'
})
.load(function() {
})
.appendTo('#someelement');
$('#whatever').attr('src', url); // trigger .load on IE

Ответ 11

Я могу дать вам небольшой совет, если вы хотите сделать вот что:

<div style="position:relative;width:100px;height:100px">
     <img src="loading.jpg" style='position:absolute;width:100px;height:100px;z-index:0'/>
     <img onLoad="$(this).fadeIn('normal').siblings('img').fadeOut('normal')" src="picture.jpg" style="display:none;position:absolute;width:100px;height:100px;z-index:1"/>
</div>

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

Ответ 12

У меня была эта проблема с IE, где e.target.width будет undefined. Событие загрузки будет срабатывать, но я не смог бы получить размеры изображения в IE (chrome + FF работал).

Оказывается, вам нужно искать e.currentTarget.naturalWidth и e.currentTarget.naturalHeight.

И снова IE делает вещи, которые он сам (более сложный).

Ответ 13

Вы можете решить свою проблему, используя JAIL плагин, который также позволяет вам ленить загружать изображения (улучшая производительность страницы) и передавать callback как параметр

$('img').asynchImageLoader({callback : function(){...}});

HTML должен выглядеть как

<img name="/global/images/sample1.jpg" src="/global/images/blank.gif" width="width" height="height" />

Ответ 14

Если вы хотите чистое решение CSS, этот трюк работает очень хорошо - используйте объект transform. Это также работает с изображениями, когда они кэшируются или нет:

CSS

.main_container{
    position: relative;
    width: 500px;
    height: 300px;
    background-color: #cccccc;
}

.center_horizontally{
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: green;
  left: 50%;
  top: 0;
  transform: translate(-50%,0);
}

.center_vertically{
  position: absolute;
  top: 50%;
  left: 0;
  width: 100px;
  height: 100px;
  background-color: blue;
  transform: translate(0,-50%);
}

.center{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  background-color: red;
  transform: translate(-50%,-50%);
}

HTML:

<div class="main_container">
  <div class="center_horizontally"></div>
  <div class="center_vertically"></div>
  <div class="center"></div>
  </div>
</div

Пример Codepen

Пример Codepen LESS

Ответ 15

попробуйте этот код:

<div class="image-wrap" data-id="3">
<img src="http://diagramcenter.org/wp-content/uploads/2016/03/image.png" class="img-load" data-id="1">
<i class="fa fa-spinner fa-spin loader-3" style="font-size:24px"></i>
</div>

<script type="text/javascript">
    jQuery(document).ready(function(){
        var allImages = jQuery(".img-load").length;
        jQuery(".img-load").each(function(){
            var image = jQuery(this);
            jQuery('<img />').attr('src', image.attr('src')).one("load",function(){
                var dataid = image.parent().attr('data-id');
                console.log(dataid);
                 console.log('load');
            });
        });

    });

</script>