Überprüfen Sie, ob ein Bild mit jQuery geladen ist (keine Fehler)


224

Ich verwende JavaScript mit der jQuery-Bibliothek, um Bildminiaturen zu bearbeiten, die in einer ungeordneten Liste enthalten sind. Wenn das Bild geladen wird, macht es eine Sache, wenn ein Fehler auftritt, macht es etwas anderes. Ich verwende jQuery load()und error()Methoden als Ereignisse. Nach diesen Ereignissen überprüfe ich das Image-DOM-Element auf .complete, um sicherzustellen, dass das Image noch nicht geladen wurde, bevor jQuery die Ereignisse registrieren konnte.

Es funktioniert ordnungsgemäß, außer wenn ein Fehler auftritt, bevor jQuery die Ereignisse registrieren kann. Die einzige Lösung, die ich mir vorstellen kann, besteht darin, das img- onerrorAttribut zu verwenden, um irgendwo global (oder auf dem Knoten selbst) ein "Flag" zu speichern, das besagt, dass es fehlgeschlagen ist, damit jQuery dieses "store / node" überprüfen kann, wenn .complete überprüft wird.

Hat jemand eine bessere Lösung?

Bearbeiten: Fettgedruckte Hauptpunkte und zusätzliche Details unten: Ich überprüfe, ob ein Bild vollständig ist (auch bekannt als geladen), nachdem ich dem Bild ein Lade- und Fehlerereignis hinzugefügt habe. Auf diese Weise weiß ich immer noch , ob das Bild vor der Registrierung der Ereignisse geladen wurde. Wenn das Bild nach den Ereignissen nicht geladen wird, kümmern sich die Ereignisse darum, wenn dies der Fall ist. Das Problem dabei ist, dass ich leicht überprüfen kann, ob ein Bild bereits geladen ist, aber nicht feststellen kann, ob stattdessen ein Fehler aufgetreten ist.


Wann registrieren Sie die jQuery-Ereignisse? Vielleicht helfen einige Codes. :)
okw

Es gibt viel Code, was ich oben gesagt habe, ist nur eine sehr einfache Version von dem, was ich tue. Ich rufe die Ereignisse auf, nachdem das DOM geladen wurde. Eine Methode wird aufgerufen, um Ereignisse zu den Miniaturansichten hinzuzufügen.
William

Antworten:


250

Eine andere Möglichkeit besteht darin, die Ereignisse onloadund / oder onerrorEreignisse auszulösen, indem ein Bildelement im Speicher erstellt und sein srcAttribut auf das ursprüngliche srcAttribut des Originalbilds gesetzt wird. Hier ist ein Beispiel dafür, was ich meine:

$("<img/>")
    .on('load', function() { console.log("image loaded correctly"); })
    .on('error', function() { console.log("error loading image"); })
    .attr("src", $(originalImage).attr("src"))
;

Hoffe das hilft!


27
Scheint nicht so gut zu funktionieren, wie ich es mir erhofft hatte. In Google Chrome scheint es Probleme zu geben, wenn sich das Bild bereits im Cache befindet. Die load () -Methode wird nicht ausgelöst. :(
William

4
Ugg, du hast recht. Chrome ist definitiv der nervigste Browser, für den man entwickeln kann. Ich glaube, ich habe eine Lösung gefunden: Setzen Sie die Bildquelle auf "" und dann zurück zur Originalquelle. Ich werde meine Antwort aktualisieren.
Xavi

1
Sie sollten die .attrZeile nach den Zeilen .loadund setzen .error. Andernfalls besteht die Gefahr, dass das Image geladen wird (oder ein Fehler auftritt), bevor diese Rückrufe hinzugefügt werden, und sie werden nicht aufgerufen.
Callum

19
@Xavi Chrome ist nicht der nervigste Browser, für den Sie entwickeln können. Versuchen Sie, für Internet Explorer 7 oder weniger zu entwickeln. Neben dem Hinzufügen eines $ _GET-Parameters zum Laden des Bildes wird jedes Mal ein neues Bild geladen, wie von Gromix vorgeschlagen.
SSH Dies

10
Die .load()und .error()Methoden sind verwirrend und jetzt veraltet. Verwenden .on()und verwenden Sie das loadund errorals Ereignisse.
Firsh - LetsWP.io

235

Überprüfen Sie die completeund naturalWidthEigenschaften, die in dieser Reihenfolge.

https://stereochro.me/ideas/detecting-broken-images-js

function IsImageOk(img) {
    // During the onload event, IE correctly identifies any images that
    // weren’t downloaded as not complete. Others should too. Gecko-based
    // browsers act like NS4 in that they report this incorrectly.
    if (!img.complete) {
        return false;
    }

    // However, they do have two very useful properties: naturalWidth and
    // naturalHeight. These give the true size of the image. If it failed
    // to load, either of these should be zero.
    if (img.naturalWidth === 0) {
        return false;
    }

    // No other way of checking: assume it’s ok.
    return true;
}

1
Interessant, ich habe mir diesen Beitrag früher angesehen und nicht bemerkt, dass sie es tun! vollständig für IE, da naturalWidth im IE nicht definiert ist. Ich werde es jetzt überprüfen.
William

3
Anscheinend funktioniert dies nur beim ersten Mal zuverlässig. Wenn Sie dann den Quellcode des Bildes ändern, meldet zumindest safari mobile weiterhin den ersten Wert für naturalWidth und complete.
Giorgian

5
return img.complete && typeof img.naturalWidth! = 'undefined' && img.naturalWidth! = 0;
Adrian Seeley

5
@vsync Sie möchten dies wahrscheinlich als einmalige Überprüfung verwenden. Wenn das Bild noch nicht geladen wurde, richten Sie einen Ereignishandler zum Laden ein. Es sollte nicht erforderlich sein, die CPU durch mehrmaliges Ausführen dieser Prüfung zu hämmern.
Michael Martin-Smucker

2
Für Neugierige ist dies ziemlich genau das, was die unten verlinkte imagesLoaded-Bibliothek tut. Also, für eine einmalige Verwendung, gehen Sie für es: github.com/desandro/imagesloaded/blob/master/…
cincodenada

57

Basierend auf meinem Verständnis der W3C-HTML-Spezifikation für das imgElement sollten Sie in der Lage sein, dies mithilfe einer Kombination der Attribute completeund zu tun naturalHeight, wie folgt:

function imgLoaded(imgElement) {
  return imgElement.complete && imgElement.naturalHeight !== 0;
}

Aus der Spezifikation für das completeAttribut:

Das IDL-Attribut complete muss true zurückgeben, wenn eine der folgenden Bedingungen erfüllt ist:

  • Das src-Attribut wird weggelassen.
  • Die letzte Aufgabe, die von der Quelle der Netzwerkaufgabe in die Warteschlange gestellt wird, nachdem die Ressource abgerufen wurde, wurde in die Warteschlange gestellt.
  • Das img-Element ist vollständig verfügbar.
  • Das img-Element ist defekt.

Andernfalls muss das Attribut false zurückgeben.

Gibt also im Wesentlichen completetrue zurück, wenn das Bild entweder vollständig geladen wurde oder nicht geladen werden konnte. Da wir nur den Fall wollen, in dem das Bild erfolgreich geladen wurde, müssen wir auch das nauturalHeightAttribut überprüfen :

Die IDL-Attribute naturalWidthund naturalHeightmüssen die intrinsische Breite und Höhe des Bildes in CSS-Pixeln zurückgeben, wenn das Bild verfügbar ist, oder 0.

Und availableist so definiert:

Ein Bild befindet sich immer in einem der folgenden Zustände:

  • Nicht verfügbar - Der Benutzeragent hat keine Bilddaten erhalten.
  • Teilweise verfügbar - Der Benutzeragent hat einige der Bilddaten erhalten.
  • Vollständig verfügbar - Der Benutzeragent hat alle Bilddaten erhalten und mindestens die Bildabmessungen sind verfügbar.
  • Defekt - Der Benutzeragent hat alle Bilddaten erhalten, die er kann, aber er kann das Bild nicht einmal genug dekodieren, um die Bildabmessungen zu erhalten (z. B. ist das Bild beschädigt oder das Format wird nicht unterstützt oder es konnten keine Daten abgerufen werden). .

Wenn sich ein img-Element entweder im teilweise verfügbaren Zustand oder im vollständig verfügbaren Zustand befindet, wird es als verfügbar bezeichnet.

Wenn das Bild also "defekt" ist (nicht geladen werden konnte), befindet es sich im defekten Zustand, nicht im verfügbaren Zustand, also naturalHeightist es 0.

Daher imgElement.complete && imgElement.naturalHeight !== 0sollte uns bei der Überprüfung mitgeteilt werden, ob das Bild erfolgreich geladen wurde.

Weitere Informationen hierzu finden Sie in der W3C-HTML-Spezifikation für das imgElement oder in MDN .


1
Funktioniert nicht,
wenn das

1
Dies scheint in Firefox mit SVG-Bildern nicht zu funktionieren, da der Browser eine natürliche Höhe / Breite von 0 meldet. Relevanter Fehler: bugzilla.mozilla.org/show_bug.cgi?id=1328124
leeb

20

Ich habe viele verschiedene Wege ausprobiert und dieser Weg ist der einzige, der für mich funktioniert hat

//check all images on the page
$('img').each(function(){
    var img = new Image();
    img.onload = function() {
        console.log($(this).attr('src') + ' - done!');
    }
    img.src = $(this).attr('src');
});

Sie können auch eine Rückruffunktion hinzufügen, die ausgelöst wird, sobald alle Bilder in das DOM geladen und bereit sind. Dies gilt auch für dynamisch hinzugefügte Bilder. http://jsfiddle.net/kalmarsh80/nrAPk/


jsfiddle Link gebrochen
Alex Karshin

1
Ich habe die oben beschriebenen interessanten Lesevorgänge getestet und sie schlagen zwischen zwischengespeicherten / nicht zwischengespeicherten Tests in einer Handvoll gängiger Browser fehl. Diese Antwort ähnelt einer anderen, ist jedoch die, die ich gerade implementiert und getestet habe. Ich kann bestätigen, dass sie funktioniert: EdgeWin10, IE11Win8.1, Win7IE10, Win7IE9, iOS 10.2 Chrome, iOS 10.2 Safari, Mac OS 10.12 Chrome, Mac OS 10.12 Safari, Mac OS 10.12 Firefox, Google Pixel 7.1, Samsung S5 Android 4.4. Vergessen Sie nicht, auch addEventListener / removeEventListener zu verwenden: D
danjah

13

Verwenden Sie die imagesLoadedJavascript-Bibliothek .

Verwendbar mit einfachem Javascript und als jQuery-Plugin.

Eigenschaften:

Ressourcen


Das hat bei mir perfekt funktioniert. Funktion checkImages (imgs) {$ (imgs) .each (function () {$ (imgs) .imagesLoaded () .progress (Funktion (Instanz, Bild) {if (image.isLoaded == false) {console.log (Bild .img.src + 'konnte nicht gefunden werden.'); image.img.src = "/templates/img/no-image.jpg";}});}); }
Rooster242

1
Es scheint eine Menge offener Probleme zu geben, die große Fehler verursachen, und die Entwickler scheinen nicht viel zu tun, um sie einzuholen. Ab sofort ist dies in einer Produktionsumgebung völlig unbrauchbar.
vsync

3
@vsync Hast du einige der offenen Fragen gelesen? Er reagiert auf fast alle und die meisten scheinen nicht reproduzierbare Randfälle zu sein, denen nur wenige andere begegnen. Ich hatte noch nie ein Problem damit in der Produktion.
Josh Harrison

1
Ja, ich benutze es selbst und manchmal funktioniert es nicht, also benutze ich ein setTimeout, um Fälle abzudecken, in denen es fehlschlägt
vsync

Es gibt gute Gründe, warum man das imagesLoaded-Plugin verwenden möchte: Die completeEigenschaft scheint nicht eindeutig unterstützt zu werden: Es kann keine zuverlässige Informationsquelle zur Browserunterstützung gefunden werden. completeDie Eigenschaft scheint auch keine klare Spezifikation zu haben: Die HTML5-Spezifikation ist die einzige, die sie erwähnt, und sie befindet sich zum Zeitpunkt des Schreibens noch in einer Entwurfsversion. Wenn Sie naturalWidth& naturalHeightnur Unterstützung IE9 +, also wenn Sie es verwenden , um herauszufinden , ob das Bild geladen ist, können Sie einige „clevere“ Trick muss es auf alten Browsern funktioniert, und Sie müssen überprüfen , Cross-Browser - Verhalten ist konsistent
Adrien Seien Sie

8

Abrufen von Informationen von Bildelementen auf der Seite
Testen der Arbeit mit Chrome und Firefox
Working jsFiddle (öffnen Sie Ihre Konsole, um das Ergebnis anzuzeigen )

$('img').each(function(){ // selecting all image element on the page

    var img = new Image($(this)); // creating image element

    img.onload = function() { // trigger if the image was loaded
        console.log($(this).attr('src') + ' - done!');
    }

    img.onerror = function() { // trigger if the image wasn't loaded
        console.log($(this).attr('src') + ' - error!');
    }

    img.onAbort = function() { // trigger if the image load was abort
        console.log($(this).attr('src') + ' - abort!');
    }

    img.src = $(this).attr('src'); // pass src to image object

    // log image attributes
    console.log(img.src);
    console.log(img.width);
    console.log(img.height);
    console.log(img.complete);

});

Hinweis: Ich habe jQuery verwendet . Ich dachte, dies kann mit vollständigem Javascript erreicht werden

Ich finde hier gute Informationen OpenClassRoom -> dies ist ein französisches Forum


3

Echtzeit-Netzwerkdetektor - Überprüfen Sie den Netzwerkstatus, ohne die Seite zu aktualisieren: aktualisieren (Es ist keine Abfrage, aber getestet und funktioniert zu 100%: (getestet in Firefox v25.0))

Code:

<script>
 function ImgLoad(myobj){
   var randomNum = Math.round(Math.random() * 10000);
   var oImg=new Image;
   oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
   oImg.onload=function(){alert('Image succesfully loaded!')}
   oImg.onerror=function(){alert('No network connection or image is not available.')}
}
window.onload=ImgLoad();
</script>

<button id="reloadbtn" onclick="ImgLoad();">Again!</button>

Wenn die Verbindung unterbrochen wird, drücken Sie einfach die Taste Erneut.

Update 1: Automatische Erkennung ohne Aktualisierung der Seite:

<script>
     function ImgLoad(myobj){
       var randomNum = Math.round(Math.random() * 10000);
       var oImg=new Image;
       oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
       oImg.onload=function(){networkstatus_div.innerHTML="";}
       oImg.onerror=function(){networkstatus_div.innerHTML="Service is not available. Please check your Internet connection!";}
}

networkchecker = window.setInterval(function(){window.onload=ImgLoad()},1000);
</script>

<div id="networkstatus_div"></div>

100%! Was passiert, wenn Ihr Image-Link von einem Proxy / einer Firewall blockiert wird oder der Image-Server nicht reagiert? Sie haben noch das Netzwerk funktioniert :)
Sen Jacob

Dadurch wird jedes Bild erneut vom Server geladen, wodurch der Cache (absichtlich) beschädigt wird. Nur zur Überprüfung verdoppeln Sie (zumindest) die Bandbreite für alle Ihre Bilder. Außerdem wird nur geprüft, ob das Image auf dem Server vorhanden ist, nicht, ob es an einem bestimmten Ort geladen wurde. Auch keine Möglichkeit zu wissen, wann jedes Bild geladen wird.
Marius Balčytis

3

Nachdem ich die interessanten Lösungen auf dieser Seite gelesen hatte, erstellte ich eine benutzerfreundliche Lösung, die stark von SLaks und Noyos Beitrag beeinflusst war und anscheinend an ziemlich aktuellen Versionen (zum Zeitpunkt des Schreibens) von Chrome, IE, Firefox, Safari und Opera (alles unter Windows). Es funktionierte auch auf einem iPhone / iPad-Emulator, den ich verwendet habe.

Ein Hauptunterschied zwischen dieser Lösung und SLaks und Noyos Beitrag besteht darin, dass diese Lösung hauptsächlich die Eigenschaften naturalWidth und naturalHeight überprüft. Ich habe festgestellt, dass diese beiden Eigenschaften in den aktuellen Browserversionen die hilfreichsten und konsistentesten Ergebnisse liefern.

Dieser Code gibt TRUE zurück, wenn ein Bild vollständig UND erfolgreich geladen wurde. Es gibt FALSE zurück, wenn ein Bild entweder noch nicht vollständig geladen wurde oder nicht geladen werden konnte.

Eine Sache, die Sie beachten müssen, ist, dass diese Funktion auch FALSE zurückgibt, wenn das Bild ein 0x0-Pixel-Bild ist. Aber diese Bilder sind ziemlich ungewöhnlich und ich kann mir keinen sehr nützlichen Fall vorstellen, in dem Sie überprüfen möchten, ob ein 0x0-Pixel-Bild bereits geladen wurde :)

Zuerst fügen wir dem HTMLImageElement-Prototyp eine neue Funktion mit dem Namen "isLoaded" hinzu, damit die Funktion für jedes Bildelement verwendet werden kann.

HTMLImageElement.prototype.isLoaded = function() {

    // See if "naturalWidth" and "naturalHeight" properties are available.
    if (typeof this.naturalWidth == 'number' && typeof this.naturalHeight == 'number')
        return !(this.naturalWidth == 0 && this.naturalHeight == 0);

    // See if "complete" property is available.
    else if (typeof this.complete == 'boolean')
        return this.complete;

    // Fallback behavior: return TRUE.
    else
        return true;

};

Jedes Mal, wenn wir den Ladestatus des Bildes überprüfen müssen, rufen wir einfach die Funktion "isLoaded" auf.

if (someImgElement.isLoaded()) {
    // YAY! The image loaded
}
else {
    // Image has not loaded yet
}

Laut Giorgians Kommentar zum Beitrag von SLaks und Noyo kann diese Lösung wahrscheinlich nur als einmalige Überprüfung von Safari Mobile verwendet werden, wenn Sie vorhaben, das SRC-Attribut zu ändern. Sie können dies jedoch umgehen, indem Sie ein Bildelement mit einem neuen SRC-Attribut erstellen, anstatt das SRC-Attribut für ein vorhandenes Bildelement zu ändern.


2

So habe ich es geschafft, browserübergreifend mit einer Kombination der oben genannten Methoden zu arbeiten (ich musste auch Bilder dynamisch in den Dom einfügen):

$('#domTarget').html('<img src="" />');

var url = '/some/image/path.png';

$('#domTarget img').load(function(){}).attr('src', url).error(function() {
    if ( isIE ) {
       var thisImg = this;
       setTimeout(function() {
          if ( ! thisImg.complete ) {
             $(thisImg).attr('src', '/web/css/img/picture-broken-url.png');
          }
       },250);
    } else {
       $(this).attr('src', '/web/css/img/picture-broken-url.png');
    }
});

Hinweis: Sie müssen einen gültigen booleschen Status für die isIE-Variable angeben.


2
var isImgLoaded = function(imgSelector){
  return $(imgSelector).prop("complete") && $(imgSelector).prop("naturalWidth") !== 0;
}

// Oder als Plugin

    $.fn.extend({
      isLoaded: function(){
        return this.prop("complete") && this.prop("naturalWidth") !== 0;
      }
    })

// $(".myImage").isLoaded() 

1

Soweit ich weiß, ist die Eigenschaft .complete nicht Standard. Es ist möglicherweise nicht universell ... Ich stelle fest, dass es in Firefox-Versen IE anders zu funktionieren scheint. Ich lade eine Reihe von Bildern in Javascript und überprüfe dann, ob sie vollständig sind. In Firefox scheint dies großartig zu funktionieren. Im IE ist dies nicht der Fall, da die Bilder anscheinend in einen anderen Thread geladen werden. Dies funktioniert nur, wenn zwischen meiner Zuweisung zu image.src und dem Überprüfen der Eigenschaft image.complete eine Verzögerung liegt.

Die Verwendung von image.onload und image.onerror funktioniert auch bei mir nicht, da ich einen Parameter übergeben muss, um zu wissen, um welches Bild es sich handelt, wenn die Funktion aufgerufen wird. Jeder Weg, dies zu tun, scheint zu scheitern, weil er tatsächlich dieselbe Funktion zu übergeben scheint, nicht verschiedene Instanzen derselben Funktion. Der Wert, den ich zur Identifizierung des Bildes eingebe, ist also immer der letzte Wert in der Schleife. Ich kann mir keinen Weg vorstellen, um dieses Problem zu umgehen.

In Safari und Chrome wird image.complete true und naturalWidth festgelegt, auch wenn in der Fehlerkonsole ein 404 für dieses Image angezeigt wird. Ich habe dieses Image absichtlich entfernt, um dies zu testen. Aber das oben genannte funktioniert gut für Firefox und IE.


Hmm, das ist interessant. Würde es etwas ausmachen, ein Codebeispiel zu veröffentlichen, damit ich ein paar Dinge ausprobieren möchte?
Xavi

1

Dieser Codeausschnitt hat mir geholfen, Probleme beim Zwischenspeichern des Browsers zu beheben:

$("#my_image").on('load', function() {

    console.log("image loaded correctly"); 
}).each(function() {

     if($(this).prop('complete')) $(this).load();
});

Wenn der Browser-Cache deaktiviert ist, funktioniert nur dieser Code nicht:

$("#my_image").on('load', function() {
     console.log("image loaded correctly"); 
})

Damit es funktioniert, müssen Sie Folgendes hinzufügen:

.each(function() {
     if($(this).prop('complete')) $(this).load();
});

0

Mit diesem JavaScriptCode können Sie überprüfen, ob das Bild erfolgreich geladen wurde oder nicht.

document.onready = function(e) {
        var imageobj = new Image();
        imageobj.src = document.getElementById('img-id').src;
        if(!imageobj.complete){ 
            alert(imageobj.src+"  -  Not Found");
        }
}

Probieren Sie das aus


0

Ich hatte viele Probleme mit dem vollständigen Laden eines Bildes und des EventListener.

Was auch immer ich versuchte, die Ergebnisse waren nicht zuverlässig.

Aber dann habe ich die Lösung gefunden. Es ist technisch gesehen nicht schön, aber jetzt hatte ich nie ein fehlgeschlagenes Laden des Bildes.

Was ich getan habe:

                    document.getElementById(currentImgID).addEventListener("load", loadListener1);
                    document.getElementById(currentImgID).addEventListener("load", loadListener2);

                function loadListener1()
                    {
                    // Load again
                    }

                function loadListener2()
                {
                    var btn = document.getElementById("addForm_WithImage"); btn.disabled = false;
                    alert("Image loaded");
                }

Anstatt das Bild einmal zu laden, lade ich es direkt nach dem ersten Mal ein zweites Mal und beide laufen durch den Eventhandler.

Alle meine Kopfschmerzen sind weg!


Übrigens: Ihr Jungs von stackoverflow hat mir schon mehr als hundert Mal geholfen. Dafür ein sehr großes Dankeschön!


0

Dieser hat gut für mich funktioniert :)

$('.progress-image').each(function(){
    var img = new Image();
    img.onload = function() {
        let imgSrc = $(this).attr('src');
        $('.progress-image').each(function(){
            if($(this).attr('src') == imgSrc){
                console.log($(this).parent().closest('.real-pack').parent().find('.shimmer').fadeOut())
            }
        })
    }
    img.src = $(this).attr('src');
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.