147 votes

Détecter l'échec du chargement d'une image en JavaScript

Existe-t-il un moyen de déterminer si un chemin d'image mène à une image réelle, c'est-à-dire de détecter si une image ne se charge pas en JavaScript.

Pour une application web, j'analyse un fichier xml et crée dynamiquement des images HTML à partir d'une liste de chemins d'accès aux images. Certains chemins d'accès à l'image peuvent ne plus exister sur le serveur, je veux donc échouer de manière élégante en détectant les images qui ne se chargent pas et en supprimant l'élément HTML img.

Note : les solutions jQuery ne pourront pas être utilisées (le patron ne veut pas utiliser jQuery, oui je sais, ne me lance pas). Je connais un moyen dans jQuery de détecter quand une image est chargée, mais pas si elle a échoué.

Mon code permet de créer des éléments img mais comment puis-je détecter si le chemin img mène à une image qui n'a pas pu être chargée ?

var imgObj = new Image();  // document.createElement("img");
imgObj.src = src;

156voto

Nikhil Points 1094

Vous pouvez essayer le code suivant. Je ne peux cependant pas garantir la compatibilité avec les navigateurs, vous devrez donc le tester.

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");

Et toute ma sympathie pour le patron réfractaire à jQuery !

71voto

Emilc Points 343

La réponse est intéressante, mais elle pose un problème. Chaque fois que vous affectez onload o onerror directement, il peut remplacer le rappel qui a été assigné précédemment. C'est pourquoi il existe une méthode intéressante qui consiste à "enregistre l'écouteur spécifié sur la cible d'événement sur laquelle il est appelé" comme on dit sur MDN . Vous pouvez enregistrer autant d'auditeurs que vous le souhaitez sur le même événement.

Permettez-moi de réécrire un peu la réponse.

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");

Le processus de chargement des ressources externes étant asynchrone, il serait encore plus intéressant d'utiliser le JavaScript moderne avec des promesses, comme dans le cas suivant.

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');
    }

);

56voto

Rafael Martins Points 411

Ceci :

<img onerror="this.src='/images/image.png'" src="...">

10voto

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

5voto

Meloman Points 1546

JQuery + CSS pour img

Avec jQuery, cela fonctionne pour moi :

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

Je peux utiliser cette image partout sur mon site web, quelle que soit sa taille, grâce à la propriété CSS3 suivante :

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

CONSEIL 1 : utiliser un image carrée d'au moins 800 x 800 pixels.

CONSEIL 2 : à utiliser avec portrait de personnes , utiliser object-position: 20% 50%;

CSS uniquement pour background-img

Pour les images d'arrière-plan manquantes, j'ai également ajouté les éléments suivants sur chacune d'entre elles background-image déclaration :

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

NOTE : ne fonctionne pas pour les images transparentes.

Côté serveur Apache

Une autre solution consiste à détecter l'image manquante avec Apache avant de l'envoyer au navigateur et de la remplacer par le contenu par défaut no-img.png.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X