Erkennen Sie, wenn ein Bild nicht in Javascript geladen werden kann

103

Gibt es eine Möglichkeit zu bestimmen, ob ein Bildpfad zu einem tatsächlichen Bild führt, dh zu erkennen, wenn ein Bild nicht in Javascript geladen werden kann.

Für eine Web-App analysiere ich eine XML-Datei und erstelle dynamisch HTML-Bilder aus einer Liste von Bildpfaden. Einige Bildpfade sind möglicherweise nicht mehr auf dem Server vorhanden, daher möchte ich ordnungsgemäß fehlschlagen, indem ich erkenne, welche Bilder nicht geladen werden können, und dieses HTML-img-Element lösche.

Hinweis JQuery-Lösungen können nicht verwendet werden (der Chef möchte JQuery nicht verwenden, ja, ich weiß, dass ich nicht damit anfangen kann). Ich kenne eine Möglichkeit in JQuery zu erkennen, wann ein Bild geladen wird, aber nicht, ob es fehlgeschlagen ist.

Mein Code zum Erstellen von IMG-Elementen, aber wie kann ich feststellen, ob der IMG-Pfad zu einem fehlgeschlagenen Laden des Bildes führt?

var imgObj = new Image();  // document.createElement("img");
imgObj.src = src;
sazr
quelle
Dies könnte Ihnen helfen: stackoverflow.com/questions/1977871/… (es ist jQuery, aber es kann Sie immer noch auf den richtigen Weg führen)
Ben Lee
versuchen Sie eine dieser google.com/…
ajax333221
2
Funny @ ajax333221 genau diese Frage ist zuerst in den Ergebnissen Ihres Links :)
SSH Dies
Schreiben Sie einen JQuery-Selektor, um einen neuen Boss zu finden ... das Internet ist ein großer Ort.
JJS

Antworten:

113

Sie können den folgenden Code ausprobieren. Ich kann jedoch nicht für die Browserkompatibilität bürgen, daher müssen Sie dies testen.

function testImage(URL) {
    var tester=new Image();
    tester.onload=imageFound;
    tester.onerror=imageNotFound;
    tester.src=URL;
}

function imageFound() {
    alert('That image is found and loaded');
}

function imageNotFound() {
    alert('That image was not found.');
}

testImage("http://foo.com/bar.jpg");

Und mein Mitgefühl für den jQuery-resistenten Chef!

Nikhil
quelle
2
Gibt es eine Idee, ob es eine Möglichkeit gibt, festzustellen, ob eine Weiterleitung auftritt?
Schnellschaltung
4
Dies funktioniert auf webKit (Epiphany, Safari, ...) nicht, je nachdem, von welchem ​​Server Sie ein Bild erhalten. Zum Beispiel sendet imgur manchmal weder ein vorhandenes Bild noch einen 404-Status, und das Fehlerereignis wird in diesem Fall nicht ausgelöst.
Das Problem dabei ist Ihre Nachricht: "Dieses Bild wurde nicht gefunden." Der Antwortcode könnte 500 oder 403 oder etwas anderes sein. Sie wissen nicht, dass es sich um eine 404 handelt. Tatsächlich ist es nicht sehr wahrscheinlich, dass es sich um eine 404 handelt, da Sie wahrscheinlich nicht versuchen würden, ein Bild zu laden, das nicht vorhanden ist.
PHP Guru
1
sollte Event-Handler anstelle von direkter Zuweisung hinzufügen
cdalxndr
50

Die Antwort ist nett, bringt aber ein Problem mit sich. Wann immer Sie onloadoder onerrordirekt zuweisen , kann es den zuvor zugewiesenen Rückruf ersetzen. Aus diesem Grund gibt es eine nette Methode, die "den angegebenen Listener auf dem EventTarget registriert, auf dem er aufgerufen wird", wie es auf MDN heißt . Sie können so viele Listener registrieren, wie Sie möchten.

Lassen Sie mich die Antwort ein wenig umschreiben.

function testImage(url) {
    var tester = new Image();
    tester.addEventListener('load', imageFound);
    tester.addEventListener('error', imageNotFound);
    tester.src = url;
}

function imageFound() {
    alert('That image is found and loaded');
}

function imageNotFound() {
    alert('That image was not found.');
}

testImage("http://foo.com/bar.jpg");

Da der Prozess zum Laden externer Ressourcen asynchron ist, wäre es noch besser, modernes JavaScript mit Versprechungen wie den folgenden zu verwenden.

function testImage(url) {

    // Define the promise
    const imgPromise = new Promise(function imgPromise(resolve, reject) {

        // Create the image
        const imgElement = new Image();

        // When image is loaded, resolve the promise
        imgElement.addEventListener('load', function imgOnLoad() {
            resolve(this);
        });

        // When there's an error during load, reject the promise
        imgElement.addEventListener('error', function imgOnError() {
            reject();
        })

        // Assign URL
        imgElement.src = url;

    });

    return imgPromise;
}

testImage("http://foo.com/bar.jpg").then(

    function fulfilled(img) {
        console.log('That image is found and loaded', img);
    },

    function rejected() {
        console.log('That image was not found');
    }

);
emil.c
quelle
2
Vielleicht fehlt mir etwas, aber wie kann die Zuweisung (tester.onload = ..) einen Rückruf ersetzen, wenn der "Tester" gerade erstellt wurde? Selbst wenn ein dunkler Teil des Codes jedem erstellten Bild ein Ereignis hinzufügt, ist es nicht offensichtlich, dass wir diese Ereignisse beibehalten möchten, um festzustellen, ob ein Bild vorhanden ist.
Jvilhena
1
Sie sind absolut richtig. In diesem speziellen Fall ist dies möglicherweise kein Problem, da es sehr wahrscheinlich ist, dass es nicht ersetzt wird. Im Allgemeinen ist das Hinzufügen eines Ereignis-Listeners jedoch besser als das direkte Zuweisen einer Methode.
emil.c
1
@ JohnWeisz Arrow-Funktionen sind anonym, daher ist das Debuggen schwieriger. Verwenden Sie sie sorgfältig.
Emil.c
10
@ GifCo Ich fühle mich nicht wohl, wenn ich eine solche Diskussion mit Ihnen fortsetze. Ich fühle mich von Ihrer Sprache beleidigt. Wenn Sie glauben, dass meine Antwort falsch oder unvollständig ist, schlagen Sie Änderungen vor und erläutern Sie Ihre Argumentation. Wenn Sie der Meinung sind, dass etwas eine schlechte Übung ist, schlagen Sie eine gute Übung mit Ihrer eigenen Antwort vor.
Emil.c
1
Warum wird hier über Pfeilfunktionen diskutiert? Es ist nicht zum Thema. Die Antwort ist in Ordnung, zumal alte Browser keine Pfeilfunktionen unterstützen (z. B. Internet Explorer).
PHP Guru
29

Dies:

<img onerror="this.src='/images/image.png'" src="...">
Rafael Martins
quelle
1
Während dies ein nützliches Attribut ist, das als Bild-Failover-Technik verwendet werden kann, wäre eine ausführlichere Antwort für die Leser hilfreich, um es zu verstehen.
Sorak
1
So kurz und so nützlich! Um es einfach zu verstecken:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM
2
@ Soraks Kommentar brachte mich vor Ekel zum Lachen. Dies ist die richtige Antwort.
user3751385
@ J0ANMM Eine andere Möglichkeit, das Bild auszublenden, besteht darin, ein leeres alt-Attribut hinzuzufügen: <img alt = "" src = "yourpicture.png">
Rick Glimmer
Ausgezeichnet! Anstatt zu einem Bild zu wechseln, drucke ich diesen Text onerror = "this.alt = 'Nicht gültiges Bild, benutze Link ^'"
verschwitzter
6
/**
 * Tests image load.
 * @param {String} url
 * @returns {Promise}
 */
function testImageUrl(url) {
  return new Promise(function(resolve, reject) {
    var image = new Image();
    image.addEventListener('load', resolve);
    image.addEventListener('error', reject);
    image.src = url;
  });
}

return testImageUrl(imageUrl).then(function imageLoaded(e) {
  return imageUrl;
})
.catch(function imageFailed(e) {
  return defaultImageUrl;
});
holmberd
quelle
4

jQuery + CSS für img

Mit jQuery funktioniert das bei mir:

$('img').error(function() {
    $(this).attr('src', '/no-img.png').addClass('no-img');
});

Und ich kann dieses Bild überall auf meiner Website verwenden, unabhängig von der Größe mit der folgenden CSS3-Eigenschaft:

img.no-img {
    object-fit: cover;
    object-position: 50% 50%;
}

TIPP 1: Verwenden Sie ein quadratisches Bild mit mindestens 800 x 800 Pixel.

TIPP 2: Zur Verwendung mit Personenporträts verwendenobject-position: 20% 50%;

CSS nur für Hintergrund-Img

Für fehlende Hintergrundbilder habe ich außerdem zu jeder background-imageDeklaration Folgendes hinzugefügt :

background-image: url('path-to-image.png'), url('no-img.png');

HINWEIS: Funktioniert nicht für transparente Bilder.

Apache-Serverseite

Eine andere Lösung besteht darin, fehlende Bilder mit Apache zu erkennen, bevor sie an den Browser gesendet und durch den Standardinhalt no-img.png ersetzt werden.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} /images/.*\.(gif|jpg|jpeg|png)$
RewriteRule .* /images/no-img.png [L,R=307]
Meloman
quelle
3

Hier ist eine Funktion, die ich für eine andere Antwort geschrieben habe: Javascript Image Url Verify . Ich weiß nicht , ob es genau das, was man braucht, aber es nutzt die verschiedenen Techniken , die Sie verwenden würden , die Handler für enthalten onload, onerror, onabortund eine allgemeine Timeout.

Da das Laden von Bildern asynchron ist, rufen Sie diese Funktion mit Ihrem Bild auf und rufen später Ihren Rückruf mit dem Ergebnis auf.

jfriend00
quelle
-19

genau wie unten:

var img = new Image(); 
img.src = imgUrl; 

if (!img.complete) {

//has picture
}
else //not{ 

}
JamesChen
quelle
3
Nee. Dies kann Sie in einigen Browsern darauf hinweisen, ob das Bild zwischengespeichert ist oder nicht. Ohne einen Rückruf zum Laden warten Sie jedoch nicht einmal einen Moment, um dem Browser die Möglichkeit zu geben, eine HTTP-Anforderung für dieses Bild zu initiieren.
ChaseMoskal
das ist nur um etwas zu sagen!
Hitmands
4
Das Laden von Bildern erfolgt asynchron.
Emil.c
@ emil.c ist es aus irgendeinem Grund nicht immer. ChaseMoskal (den ich SO nicht benachrichtigen lassen werde ...) hat es richtig gemacht - dies funktioniert nur, wenn das Laden des Images abgeschlossen ist, bevor die JS-Ausführung fortgesetzt wird. Dies scheint immer dann zu geschehen, wenn es zwischengespeichert wird.
Tristan