jQuery-Rückruf beim Laden des Bildes (auch wenn das Bild zwischengespeichert ist)

291

Ich will das tun:

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

Das Ladeereignis wird jedoch nicht ausgelöst, wenn das Bild aus dem Cache geladen wird. Die jQuery-Dokumente schlagen ein Plugin vor , um dies zu beheben, aber es funktioniert nicht

Tom Lehman
quelle
12
Seit Ihrer Frage haben sich die Dinge geändert. Das kaputte Plugin wurde in einen Kern und später in ein Repo mit einem kleinen funktionierenden Plugin jQuery.imagesLoaded verschoben . Sie beheben alle kleinen Browser-Macken .
Lode
Die oben erwähnte JQuery-Bibliothek hat für mich einwandfrei funktioniert. Vielen Dank!
Plang
Danke für das Plugin, es hat gut funktioniert.
Onimojo

Antworten:

572

Wenn das srcbereits festgelegt ist, wird das Ereignis im zwischengespeicherten Fall ausgelöst, bevor Sie den Ereignishandler überhaupt gebunden bekommen. Um dies zu beheben, können Sie das Ereignis .completewie folgt überprüfen und auslösen :

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

Beachten Sie den Wechsel von .bind()zu, .one()damit der Ereignishandler nicht zweimal ausgeführt wird.

Nick Craver
quelle
8
Ihre Lösung hat für mich perfekt funktioniert, aber ich möchte etwas verstehen, wenn dieser Code "if (this.complete)" ausgeführt wird, nachdem der Bildinhalt geladen wurde oder vorher? denn wie ich aus dieser .each verstehen kann, schleifen Sie alle $ ("img") und möglicherweise ist der Bildinhalt leer und das Laden wird nicht stattfinden. hmmmm, ich denke ich habe etwas vermisst, es wird schön sein wenn man beschreiben kann das das besser verstehen wird. Vielen Dank.
Amr Elgarhy
33
Seit Ihrer Antwort haben sich die Dinge geändert. Es gibt jetzt ein kleines funktionierendes Plugin jQuery.imagesLoaded . Sie beheben alle kleinen Browser-Macken .
Lode
3
Ich würde ein setTimeout(function(){//do stuff},0)innerhalb der 'Lade'-Funktion hinzufügen ... die 0 gibt dem Browsersystem (DOM) ein zusätzliches Häkchen, um sicherzustellen, dass alles richtig aktualisiert wird.
dsdsdsdsd
14
@Lode - es ist ein RIESIGES Plugin, in keiner Größenordnung klein !!
vsync
5
Da die JQuery 3-Methode .load()kein Ereignis auslöst und 1 erforderliches Argument hat, verwenden Sie .trigger("load")stattdessen
ForceUser
48

Kann ich vorschlagen, dass Sie es erneut in ein Nicht-DOM-Bildobjekt laden? Wenn es zwischengespeichert ist, dauert dies überhaupt keine Zeit und die Onload wird immer noch ausgelöst. Wenn es nicht zwischengespeichert ist, wird der Onload ausgelöst, wenn das Image geladen wird. Dies sollte die gleiche Zeit sein, zu der die DOM-Version des Images den Ladevorgang beendet hat.

Javascript:

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

Aktualisiert (um mehrere Bilder zu verarbeiten und mit korrekt bestelltem Onload-Anhang):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;
Gus
quelle
1
Sie sollten versuchen, den loadHandler anzuhängen, bevor er hinzugefügt wird. Auch dies funktioniert nicht, aber für ein Bild funktioniert der OP-Code für viele :)
Nick Craver
Vielen Dank, ich habe eine aktualisierte Version hinzugefügt, die hoffentlich diese beiden Probleme behebt.
Gus
#imgist eine ID, keine Elementauswahl :) Funktioniert auch this.src, es ist nicht erforderlich, jQuery dort zu verwenden, wo es nicht benötigt wird :) Aber das Erstellen eines anderen Bildes scheint in beiden Fällen übertrieben zu sein, IMO.
Nick Craver
es sollte $ ('img') sein. aber Lösung ist gr8 in 2k15 auch
Dimag Kharab
Wenn Sie für den Fall mit mehreren imageLoadedtmp.onload = imageLoaded.bind(this)
Bildern
38

Meine einfache Lösung, es benötigt kein externes Plugin und sollte für häufige Fälle ausreichen:

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

benutze es so:

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

Zum Einblenden Ihrer Bilder beim Laden können Sie beispielsweise Folgendes tun:

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

Oder alternativ, wenn Sie einen jquery-Plugin-ähnlichen Ansatz bevorzugen:

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

und benutze es so:

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

beispielsweise:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});
Guari
quelle
urm .. und was ist, wenn meine Bilder eine mit CSS eingestellte Größe haben?
Simon_Weaver
Set width, max-heightund verlassen height:auto, ist es oft notwendig , sowohl die Breite und Höhe nur einstellen , wenn Sie das Bild strecken müssen; Für eine robustere Lösung würde ich ein Plugin wie ImagesLoaded
Guari
1
Ja , es war ein Tippfehler, jsdoc war ok, ich die Zeile Beispiel korrigiert
guari
1
Diese Lösung mit $ .fn.imgLoad funktioniert browserübergreifend. Das Problem wird noch besser behoben: && / * für IE 10 - * / this.naturalHeight> 0 In dieser Zeile wird der CSS-Stil nicht berücksichtigt, da img blockiert werden kann, aber eine Höhe hat. Arbeit in IE10
Patryk Padus
1
Dies hat eine (kleine) Rennbedingung. Das Image kann in einem anderen Thread als das Skript geladen werden und kann daher zwischen der Überprüfung des Abschlusses und dem Anhängen des Onload-Ereignisses geladen werden. In diesem Fall geschieht nichts. Normalerweise ist JS mit dem Rendering synchron und Sie müssen sich keine Gedanken über die Rennbedingungen machen, aber dies ist eine Ausnahme. html.spec.whatwg.org/multipage/…
Mog0
23

Müssen Sie das wirklich mit jQuery machen? Sie können das onloadEreignis auch direkt an Ihr Bild anhängen .

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

Es wird jedes Mal ausgelöst, wenn das Bild geladen wurde, aus dem Cache oder nicht.

Björn
quelle
5
Es ist sauberer ohne Inline-Javascript
Haselnuss
1
Hallo Björn, wird der onloadHandler ausgelöst, wenn das Bild ein zweites Mal aus dem Cache geladen wird?
SexyBeast
1
@Cupidvogel nein wird es nicht.
Anzeigen
3
Alter, du hast mir das Leben gerettet, ich habe mindestens ein Dutzend anderer Lösungen ausprobiert und deine ist die einzige, die tatsächlich funktioniert hat. Ich denke ernsthaft darüber nach, 10 weitere Konten zu erstellen, um Ihre Antwort noch 10 Mal abzustimmen. Im Ernst, danke!
Carlo
1
Ich habe die Abneigung der Leute gegen Inline-JS nie verstanden. Das Laden der Bilder erfolgt getrennt und außerhalb der Reihenfolge des restlichen Ladevorgangs der Seite. Daher ist dies die einzig gültige Lösung, um sofortiges Feedback zum Abschluss des Bildladens zu erhalten. Wenn jedoch jemand auf das Laden von jQuery warten muss und dies später geschieht, muss er die einfache Lösung hier nicht verwenden und eine der anderen Lösungen verwenden (Piotr ist wahrscheinlich die beste Option, da es nicht von Pseudo- abhängig ist) Hacks, aber Guaris Höhe () Check könnte auch wichtig sein). Eine Verarbeitungswarteschlange könnte ebenfalls nützlich sein.
CubicleSoft
16

Sie können diesen Code auch mit Unterstützung für Ladefehler verwenden:

$("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();
    }
});
Piotr Stępniewski
quelle
1
Dieser hat am besten für mich funktioniert. Ich denke, der Schlüssel ist, zuerst den loadHandler zu setzen und ihn später in der eachFunktion aufzurufen .
GreenRaccoon23
Einstellen des Bildes mit dem folgenden Code '' var img = new Image (); img.src = sosImgURL; $ (img) .on ("load", function () {''
imdadhusen
13

Ich hatte gerade dieses Problem selbst und suchte überall nach einer Lösung, bei der ich meinen Cache nicht tötete oder ein Plugin herunterlud.

Ich habe diesen Thread nicht sofort gesehen, also habe ich stattdessen etwas anderes gefunden, das eine interessante Lösung darstellt und (ich denke) es wert ist, hier veröffentlicht zu werden:

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

Ich habe diese Idee tatsächlich aus den Kommentaren hier erhalten: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

Ich habe keine Ahnung, warum es funktioniert, aber ich habe dies auf IE7 getestet und wo es kaputt gegangen ist, bevor es jetzt funktioniert.

Ich hoffe es hilft,

Bearbeiten

Die akzeptierte Antwort erklärt tatsächlich, warum:

Wenn der src bereits festgelegt ist, wird das Ereignis im Cache ausgelöst, bevor der Ereignishandler gebunden wird.

Sammaye
quelle
4
Ich habe getestet, dass dies in vielen Browsern vorkommt, und habe nirgendwo einen Fehler festgestellt. Ich habe $image.load(function(){ something(); }).attr('src', $image.attr('src'));die ursprüngliche Quelle zurückgesetzt.
Maurice
Ich habe festgestellt, dass dieser Ansatz unter iOS nicht funktioniert, zumindest für Safari / 601.1 und Safari / 602.1
Cronfy
Es wäre großartig herauszufinden, warum, in welchem ​​Browser es sich befindet.
Sammaye
5

Indem Sie mit jQuery ein neues Bild mit dem src des Bildes generieren und die Lademethode direkt diesem zuweisen, wird die Lademethode erfolgreich aufgerufen, wenn jQuery die Generierung des neuen Bildes abgeschlossen hat. Dies funktioniert für mich in IE 8, 9 und 10

$('<img />', {
    "src": $("#img").attr("src")
}).load(function(){
    // Do something
});
Nick
quelle
Für diejenigen, die Ruby on Rails mit Remote-Anfrage und __rjs.erb-Vorlagen verwenden, ist dies die einzige Lösung, die ich gefunden habe. Da bei Verwendung von Partials in js.erb die Bindung verloren geht ($ ("# img" .on ("load") ...) und für Bilder die "on" -Methode NICHT delegiert werden kann: $ ("body"). on ("load", "# img", function () ...
Albert Català
5

Eine Lösung, die ich gefunden habe https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (Dieser Code stammt direkt aus dem Kommentar)

var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;
AllisonC
quelle
Genau das habe ich gesucht. Ein einzelnes Bild kommt vom Server zu mir. Ich wollte es vorladen und dann dienen. Nicht alle Bilder auswählen, wie es viele Antworten tun. Gut.
Kai Qing
4

Eine Modifikation des GUS-Beispiels:

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

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

Stellen Sie die Quelle vor und nach dem Onload ein.

Chuck Conway
quelle
Wie bei der Antwort von @ Gus funktioniert dies nicht für mehrere Bilder ... und es ist nicht erforderlich, die Einstellung srcvor dem Anhängen des onloadHandlers festzulegen. Ein einziges Mal danach reicht aus.
Nick Craver
3

Fügen Sie das src-Argument einfach in einer separaten Zeile hinzu, nachdem das img-Objekt definiert wurde. Dies wird den IE dazu bringen, das Lad-Ereignis auszulösen. Es ist hässlich, aber es ist die einfachste Problemumgehung, die ich bisher gefunden habe.

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

Ich kann Ihnen einen kleinen Tipp geben, wenn Sie dies möchten:

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

Wenn Sie dies tun, wenn der Browser Bilder zwischenspeichert, ist es kein Problem, immer img angezeigt zu werden, sondern img unter realem Bild zu laden.

Josephy Besim
quelle
1

Ich hatte dieses Problem mit dem Internet Explorer, bei dem die e.target.width undefiniert war. Das Ladeereignis würde ausgelöst, aber ich konnte die Abmessungen des Bildes im IE nicht ermitteln (Chrome + FF funktionierte).

Es stellt sich heraus, dass Sie nach e.currentTarget.naturalWidth & e.currentTarget.naturalHeight suchen müssen .

Wieder einmal macht der IE Dinge auf seine eigene (kompliziertere) Weise.

Ali
quelle
0

Sie können Ihr Problem mit dem JAIL- Plugin lösen, mit dem Sie auch Bilder verzögert laden (was die Seitenleistung verbessert) und den Rückruf als Parameter übergeben können

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

Der HTML-Code sollte so aussehen

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

Wenn Sie eine reine CSS-Lösung wünschen, funktioniert dieser Trick sehr gut - verwenden Sie das Transformationsobjekt. Dies funktioniert auch mit Bildern, wenn sie zwischengespeichert sind oder nicht:

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 Beispiel

Codepen WENIGER Beispiel

neoRiley
quelle
Können Sie ein Beispiel geben, wie dies beim Laden von Bildern funktioniert?
Hastig Zusammenstellen