jQuery görüntü yüklemesinde geri arama (görüntü önbelleğe alınmış olsa bile)


291

Ben yapmak istiyorum:

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

Ancak görüntü önbellekten yüklendiğinde load olayı tetiklenmez. JQuery dokümanlar önermek bir eklentisi bu sorunu gidermek için, ama o işi yapmaz


12
Sorunuzdan beri işler değişti. Bozuk eklenti bir gist'e ve daha sonra küçük bir eklenti jQuery.imagesLoaded ile bir repoya taşındı . Tüm küçük tarayıcı tuhaflıklarını düzeltirler .
Lode

Yukarıda belirtilen JQuery kütüphanesi benim için gayet iyi çalıştı. Teşekkürler!
plang

Eklenti için teşekkür ederim, iyi çalıştı.
onimojo

Yanıtlar:


572

Eğer srczaten ayarlanmışsa, olay işleyicisini bağlamadan önce olay önbelleğe alınmış durumda tetiklenir. Bunu düzeltmek için, şu şekilde etkinliğe dayalı olarak etkinliği kontrol etme ve tetikleme arasında geçiş yapabilirsiniz .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 
  }
});

Dan değişikliği Not .bind()için .one()olay işleyicisi iki kez çalışmayacak şekilde.


8
Çözümünüz benim için mükemmel çalıştı ama bir şey anlamak istiyorum, ne zaman bu kod "if (this.complete)" çalışacak, görüntü içeriği yüklendikten sonra veya daha önce? çünkü bunu anlayabildiğim gibi, tüm $ ("img") üzerinde döngü yaptığınız ve görüntü içeriği boş olabileceği ve yükleme gerçekleşmeyeceği için. hmmmm, sanırım eksik bir şeyim var, bunu daha iyi anlamaya devam ettiğini açıklayabilirsen iyi olur. Teşekkürler.
Amr Elgarhy

33
Cevabınızdan bu yana işler değişti. Şimdi jQuery.imagesLoaded küçük bir çalışma eklentisi var . Tüm küçük tarayıcı tuhaflıklarını düzeltirler .
Lode

3
Ben setTimeout(function(){//do stuff},0)'yük' fonksiyonu içinde eklemek istiyorum ... 0 tarayıcı sistemi (DOM) her şeyin düzgün şekilde güncellenmesini sağlamak için bir ekstra kene verir.
dsdsdsdsd

14
@Lode - BÜYÜK bir eklenti, herhangi bir ölçekte hiç küçük değil !!
vsync

5
JQuery 3 yöntemi .load()olayı tetiklemediğinden ve 1 gerekli bağımsız değişkeni olduğundan, .trigger("load")bunun yerine kullanın
ForceUser

48

DOM olmayan bir resim nesnesine yeniden yüklemenizi önerebilir miyim? Önbelleğe alınırsa, bu hiç zaman almaz ve yükleme yine de tetiklenir. Önbelleğe alınmazsa, görüntü yüklendiğinde, görüntünün DOM sürümünün yüklenmesi bittiğinde olması gereken yükleme yükünü tetikler.

JavaScript:

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

Güncelleme (birden fazla görüntüyü işlemek ve doğru sıralı yükleme eki ile):

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

1
loadEkleyiciyi eklemeden önce eklemeyi denemelisiniz , bu da işe yaramaz, ancak bir görüntü için OPs kodu birçok kişi için çalışır :)
Nick Craver

Teşekkürler, umarım bu iki konuyu ele alacağımı umuyorum.
Gus

#imgbir eleman seçici değil bir kimlik :) Ayrıca this.srcçalışır, jQuery gerekli değildir kullanmanıza gerek yok :) Ama başka bir görüntü oluşturmak her iki durumda IMO overkill gibi görünüyor.
Nick Craver

$ ('img') olmalıdır. ama çözüm 2k15'de de gr8
Dimag Kharab

Ayrıca, birden fazla görüntü durumunda, içindeki her görüntü için DOM öğesinde çalışmak istiyorsanız imageLoaded, kullanıntmp.onload = imageLoaded.bind(this)
blisstdev

38

Benim basit çözümüm, herhangi bir harici eklentiye ihtiyaç duymuyor ve yaygın durumlar için yeterli olmalı:

/**
 * 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);
            });
        }
    });
};

şöyle kullanın:

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

örneğin, yüklenen görüntülerinizde kaybolmak için şunları yapabilirsiniz:

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

Alternatif olarak, jquery eklentisi benzeri bir yaklaşımı tercih ederseniz:

/**
 * 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);

ve bu şekilde kullanın:

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

Örneğin:

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

urm .. ve resimlerim css ile ayarlanmış bir boyuta sahipse ne olur?
Simon_Weaver

Set width, max-heightve bırakın height:auto, genellikle genişlik ve görüntüyü genişletmek için ihtiyaç yalnızca yüksekliğini hem ayarlamak için gerekli var; daha sağlam bir çözüm için ImagesLoaded
guari

1
evet bu bir yanlış yazıyordu, jsdoc iyiydi, çizgi örneğini düzelttim
guari

1
$ .Fn.imgLoad ile bu çözüm tarayıcılarda çalışır. Düzeltmek daha da iyi olacak: IE 10 için && / * - * / this.naturalHeight> 0 img engellenebileceği, ancak yüksekliği olabileceğinden bu satır dikkate alınmaz. IE10'da çalışma
Patryk Padus

1
Bunun (küçük) bir yarış durumu var. Görüntü komut dosyasına farklı bir iş parçacığında yükleniyor olabilir ve bu nedenle tamamlanma kontrolü ile onload olayının eklenmesi arasında yüklenebilir, bu durumda hiçbir şey olmaz. Normalde JS görüntü oluşturma ile eşzamanlıdır ve bu nedenle yarış koşulları hakkında endişelenmenize gerek yoktur, ancak bu bir istisnadır. html.spec.whatwg.org/multipage/…
Mog0

23

Gerçekten jQuery ile yapmak zorunda mısın? onloadEtkinliği doğrudan resminize de ekleyebilirsiniz ;

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

Görüntü her yüklendiğinde, önbellekten ya da önlenmeden tetiklenir.


5
Satır içi javascript olmadan temiz
fındık

1
Merhaba Bjorn, onloadgörüntü önbellekten ikinci kez yüklendiğinde işleyici patlayacak mı?
SexyBeast

1
@Cupidvogel hayır olmayacak.
Reklamlar

3
Dostum, hayatımı kurtardın, en az bir düzine başka çözüm denedim ve gerçekten işe yarayan tek çözüm senindir. Cevabınızı 10 kez daha oylayabilmek için 10 hesap daha oluşturmayı düşünüyorum. Cidden teşekkürler!
Carlo

1
İnsanların satır içi JS'ye olan isteklerini hiç anlamadım. Görüntü yükleme, sayfa yükleme işleminin geri kalanından ayrı ve sırayla gerçekleşir. Bu nedenle, görüntü yükleme tamamlanması hakkında anında geri bildirim almanın tek geçerli çözümü budur. Ancak, bir kişinin jQuery'nin yüklenmesini beklemesi gerekiyorsa ve daha sonra gerçekleşirse, burada basit çözümü kullanmamalı ve diğer çözümlerden birini kullanmaları gerekmeyecektir (Piotr's muhtemelen en iyi seçenektir, çünkü sözde- kesmek ama guari'nin yükseklik () kontrolü de önemli olabilir). Bir işleme kuyruğu da yararlı olabilir.
CubicleSoft

16

Bu kodu yükleme hatası desteğiyle de kullanabilirsiniz:

$("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();
    }
});

1
Bu benim için en iyi sonucu verdi. Bence anahtar önce loadişleyiciyi ayarlamak ve daha sonra eachfonksiyonda çağırmaktır .
GreenRaccoon23

aşağıdaki kodu kullanarak görüntü ayarlama '' var img = new Image (); img.src = sosİmgURL; $ (img) .on ("yük", işlev () {''
imdadhusen

13

Bu sorunu kendim yaşadım, her yerde önbelleğimi öldürmeyi veya bir eklenti indirmeyi içermeyen bir çözüm aradım.

Ben hemen bu konu görmedim, bu yüzden ilginç bir düzeltme ve (sanırım) burada gönderme layık başka bir şey buldum:

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

Aslında bu fikri buradaki yorumlardan aldım: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

Neden çalıştığı hakkında hiçbir fikrim yok ama bunu IE7'de test ettim ve şimdi işe yaramadan önce nerede kırıldı.

Umarım yardımcı olur,

Düzenle

Kabul edilen cevap aslında nedenini açıklar:

Src zaten ayarlanmışsa, olay işleyicisini bağlamadan önce olay önbellek kasasında başlatılır.


4
Bu bir sürü tarayıcıda test ve herhangi bir yerde başarısız bulamadık. Kullandığım $image.load(function(){ something(); }).attr('src', $image.attr('src'));orijinal kaynağını sıfırlamak için.
Maurice

Bu yaklaşımın iOS'ta işe yaramadığını tespit ettim, en azından Safari / 601.1 ve Safari / 602.1
cronfy

Neden, hangi tarayıcıda olduğunu bulmak harika olurdu?
Sammaye

5

Görüntünün src'si ile yeni bir görüntü oluşturmak için jQuery kullanarak ve yükleme yöntemini doğrudan buna atayarak, jQuery yeni görüntü oluşturmayı bitirdiğinde yükleme yöntemi başarıyla çağrılır. IE 8, 9 ve 10'da bu benim için çalışıyor

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

Ruby on Rails'i kullananlar için, uzaktan istekle, __rjs.erb şablonları kullanan kişiler için bulduğum tek çözüm budur. Çünkü js.erb'de kısmi kullanmak, de bağlamayı kaybeder ($ ("# img" .on ("load") ... ve resimler için "on" yöntemini devretmek mümkün DEĞİLDİR: $ ("body"). ("load", "# img", function () ...
Albert Català

5

Https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 bulduğum bir çözüm (Bu kod doğrudan yorumdan alınmıştır)

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

Tam da aradığım şey buydu. Sunucudan bana tek bir görüntü geliyor. Önceden yüklemek ve sonra hizmet etmek istedim. Birçok cevap gibi tüm görüntüleri seçmemek. İyi bir.
Kai Qing

4

GUS örneğinde bir değişiklik:

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

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

Yüklemeden önce ve sonra kaynağı ayarlayın.


@ Gus'ın yanıtı gibi, bu birden fazla görüntü için işe yaramaz ... ve işleyiciyi srctakmadan önce ayarlamaya gerek yoktur onload, bir kez sonra yeterli olacaktır.
Nick Craver

3

İmg oject tanımlandıktan sonra src bağımsız değişkenini ayrı bir satıra yeniden ekleyin. Bu, lad-olayı tetiklemek için IE'yi kandırır. Bu çirkin ama şimdiye kadar bulduğum en basit çözüm.

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

1

Bunu yapmak isterseniz size küçük bir ipucu verebilirim:

<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>

Tarayıcı resimleri önbelleğe aldığında bunu yaparsanız, her zaman gösterilen img sorun değil, gerçek resim altında img yükleniyor.


1

Ben e.target.width undefined olacağını IE ile bu sorunu vardı. Load olayı tetiklenirdi ancak IE'de (chrome + FF çalıştı) görüntünün boyutlarını alamadım.

E.currentTarget.naturalWidth & e.currentTarget.naturalHeight'ı aramanız gerektiği ortaya çıkıyor .

IE bir kez daha kendi (daha karmaşık) yolunu yapıyor.


0

Sorunları, görüntüleri tembel yüklemenize (sayfa performansını iyileştirmek) ve geri aramayı parametre olarak iletmenize izin veren JAIL eklentisini kullanarak çözebilirsiniz.

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

HTML şöyle görünmelidir

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

0

Saf bir CSS çözümü istiyorsanız, bu hile çok iyi çalışır - dönüştürme nesnesini kullanın. Bu, önbelleğe alındıklarında veya önlenmediklerinde resimlerle de çalışır:

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 örneği

Codepen LESS örneği


Bunun resim yükleme ile nasıl çalıştığına bir örnek verebilir misiniz?
Hastig Zusammenstellen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.