web-dev-qa-db-fra.com

jQuery / JavaScript pour remplacer les images brisées

J'ai une page Web qui comprend un tas d'images. Parfois, l'image n'est pas disponible et une image endommagée s'affiche dans le navigateur du client.

Comment utiliser jQuery pour obtenir le jeu d'images, le filtrer en images brisées, puis remplacer le fichier src?


--Je pensais qu'il serait plus facile de faire cela avec jQuery, mais il s'est avéré beaucoup plus facile d'utiliser une solution purement JavaScript, c'est-à-dire celle fournie par Prestaul.

521
Dan Lord

Gérez l'événement onError pour que l'image réaffecte sa source à l'aide de JavaScript:

function imgError(image) {
    image.onerror = "";
    image.src = "/images/noimage.gif";
    return true;
}
<img src="image.png" onerror="imgError(this);"/>

Ou sans fonction JavaScript:

<img src="image.png" onError="this.onerror=null;this.src='/images/noimage.gif';" />

Le tableau de compatibilité suivant répertorie les navigateurs prenant en charge la fonction d'erreur:

http://www.quirksmode.org/dom/events/error.html

722
Prestaul

J'utilise le gestionnaire intégré error:

$("img").error(function () {
    $(this).unbind("error").attr("src", "broken.gif");
});

Edit: La méthode error() est obsolète en jquery 1.8 et plus. Au lieu de cela, vous devriez utiliser .on("error") à la place:

$("img").on("error", function () {
    $(this).attr("src", "broken.gif");
});
193
travis

Au cas où quelqu'un comme moi essaierait de lier l'événement error à une balise HTML dynamique img, j'aimerais signaler qu'il existe un inconvénient:

Apparemment img événements d'erreur ne pas afficher de bulles dans la plupart des navigateurs, contrairement à ce que standard) dit.

Donc, quelque chose comme ce qui suit ne fonctionnera pas :

$(document).on('error', 'img', function () { ... })

J'espère que cela sera utile à quelqu'un d'autre. J'aurais aimé l'avoir vu ici dans ce fil. Mais je ne l'ai pas fait. Donc, je l'ajoute

115
mouad

Voici une solution autonome:

$(window).load(function() {
  $('img').each(function() {
    if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
      // image was broken, replace with your new image
      this.src = 'http://www.tranism.com/weblog/images/broken_iPod.gif';
    }
  });
});
55
Devon

Je crois que c'est ce que vous recherchez: jQuery.Preload

Voici l'exemple de code de la démo, vous spécifiez le chargement et les images non trouvées et vous êtes tous ensemble:

$('#images img').preload({
    placeholder:'placeholder.jpg',
    notFound:'notfound.jpg'
});
32
Nick Craver
$(window).bind('load', function() {
$('img').each(function() {
    if((typeof this.naturalWidth != "undefined" &&
        this.naturalWidth == 0 ) 
        || this.readyState == 'uninitialized' ) {
        $(this).attr('src', 'missing.jpg');
    }
}); })

Source: http://www.developria.com/2009/03/jquery-quickie---broken-images.html

23
Mohamad

Alors que le PO cherchait à remplacer le SRC, je suis sûr que beaucoup de personnes qui ont répondu à cette question souhaiteraient peut-être seulement cacher l’image brisée, auquel cas cette solution simple a fonctionné à merveille pour moi:

<img src="img.jpg" onerror="this.style.display='none';" />
12
Nathan Arthur

Voici un moyen simple et rapide de remplacer toutes les images brisées, et il n’est pas nécessaire de changer le code HTML;)

exemple de code

    $("img").each(function(){
        var img = $(this);
        var image = new Image();
        image.src = $(img).attr("src");
        var no_image = "https://dummyimage.com/100x100/7080b5/000000&text=No+image";
        if (image.naturalWidth == 0 || image.readyState == 'uninitialized'){
            $(img).unbind("error").attr("src", no_image).css({
                height: $(img).css("height"),
                width: $(img).css("width"),
            });
        }
  });
10
Ashfaq Ahmed

Je ne pouvais pas trouver de script adapté à mes besoins. J'ai donc créé une fonction récursive pour rechercher les images brisées et essayer de les recharger toutes les quatre secondes jusqu'à ce qu'elles soient corrigées.

Je l'ai limité à 10 tentatives, car si l'image n'était pas chargée, l'image pourrait ne pas être présente sur le serveur et la fonction entrerait dans une boucle infinie. Je teste toujours bien. N'hésitez pas à le modifier :)

var retries = 0;
$.imgReload = function() {
    var loaded = 1;

    $("img").each(function() {
        if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {

            var src = $(this).attr("src");
            var date = new Date();
            $(this).attr("src", src + "?v=" + date.getTime()); //slightly change url to prevent loading from cache
            loaded =0;
        }
    });

    retries +=1;
    if (retries < 10) { // If after 10 retries error images are not fixed maybe because they
                        // are not present on server, the recursion will break the loop
        if (loaded == 0) {
            setTimeout('$.imgReload()',4000); // I think 4 seconds is enough to load a small image (<50k) from a slow server
        }
        // All images have been loaded
        else {
            // alert("images loaded");
        }
    }
    // If error images cannot be loaded  after 10 retries
    else {
        // alert("recursion exceeded");
    }
}

jQuery(document).ready(function() {
    setTimeout('$.imgReload()',5000);
});
8
Shade

C'est une technique de merde, mais c'est à peu près garanti:

<img ...  onerror="this.parentNode.removeChild(this);">
8
Phil LaNasa

Ceci est JavaScript, devrait être compatible avec tous les navigateurs et fonctionne sans le balisage moche onerror="":

var sPathToDefaultImg = 'http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png',
    validateImage = function( domImg ) {
        oImg = new Image();
        oImg.onerror = function() {
            domImg.src = sPathToDefaultImg;
        };
        oImg.src = domImg.src;
    },
    aImg = document.getElementsByTagName( 'IMG' ),
    i = aImg.length;

while ( i-- ) {
    validateImage( aImg[i] );
}

CODEPEN:

5
Axel

Vous pouvez utiliser le propre récupération de GitHub pour cela:

Frontend: https://github.com/github/fetch
ou pour Backend, une version de Node.js: https://github.com/bitinn/node-fetch

fetch(url)
  .then(function(res) {
    if (res.status == '200') {
      return image;
    } else {
      return placeholder;
    }
  }

Edit: Cette méthode remplacera XHR et aurait déjà été utilisée dans Chrome. Ceux qui liront ceci à l’avenir n'auront peut-être pas besoin de la bibliothèque susmentionnée.

5
BarryMode

Si vous avez inséré votre img avec innerHTML, comme: $("div").innerHTML = <img src="wrong-uri">, vous pouvez charger une autre image si elle ne parvient pas, par exemple, ceci:

<script>
    function imgError(img) {
        img.error="";
        img.src="valid-uri";
    }
</script>

<img src="wrong-uri" onerror="javascript:imgError(this)">

Pourquoi javascript: _ est-il nécessaire? Comme les scripts injectés dans le DOM via les balises de script dans innerHTML ne sont pas exécutés au moment de leur injection, vous devez donc être explicite.

4
horro

Voici un exemple d'utilisation de l'objet Image HTML5 enveloppé par JQuery. Appelez la fonction de chargement pour l'URL de l'image principale et si ce chargement provoque une erreur, remplacez l'attribut src de l'image par une URL de sauvegarde.

function loadImageUseBackupUrlOnError(imgId, primaryUrl, backupUrl) {
    var $img = $('#' + imgId);
    $(new Image()).load().error(function() {
        $img.attr('src', backupUrl);
    }).attr('src', primaryUrl)
}

<img id="myImage" src="primary-image-url"/>
<script>
    loadImageUseBackupUrlOnError('myImage','primary-image-url','backup-image-url');
</script>
4
Kurt Hartmann

J'ai créé un violon pour remplacer l'image brisée en utilisant l'événement "onerror". Cela peut vous aider.

    //the placeholder image url
    var defaultUrl = "url('https://sadasd/image02.png')";

    $('div').each(function(index, item) {
      var currentUrl = $(item).css("background-image").replace(/^url\(['"](.+)['"]\)/, '$1');
      $('<img>', {
        src: currentUrl
      }).on("error", function(e) {
        $this = $(this);
        $this.css({
          "background-image": defaultUrl
        })
        e.target.remove()
      }.bind(this))
    })
4
Ninjaneer

En utilisant réponse de Prestaul , j'ai ajouté quelques vérifications et je préfère utiliser la méthode jQuery.

<img src="image1.png" onerror="imgError(this,1);"/>
<img src="image2.png" onerror="imgError(this,2);"/>

function imgError(image, type) {
    if (typeof jQuery !== 'undefined') {
       var imgWidth=$(image).attr("width");
       var imgHeight=$(image).attr("height");

        // Type 1 puts a placeholder image
        // Type 2 hides img tag
        if (type == 1) {
            if (typeof imgWidth !== 'undefined' && typeof imgHeight !== 'undefined') {
                $(image).attr("src", "http://lorempixel.com/" + imgWidth + "/" + imgHeight + "/");
            } else {
               $(image).attr("src", "http://lorempixel.com/200/200/");
            }
        } else if (type == 2) {
            $(image).hide();
        }
    }
    return true;
}
4
trante

Mieux appeler en utilisant

jQuery(window).load(function(){
    $.imgReload();
});

Parce que l'utilisation de document.ready n'implique pas nécessairement que les images sont chargées, uniquement le code HTML. Ainsi, il n'y a pas besoin d'un appel retardé.

4
Shade

CoffeeScript variante:

Je l'ai fait pour résoudre un problème avec Turbolinks qui provoque la levée de la méthode .error () dans Firefox parfois même si l'image est vraiment là.

$("img").error ->
  e = $(@).get 0
  $(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)
4
Kevin

Pure JS. Ma tâche était: si l'image 'bl-once.png' est vide -> insère la première (qui n'a pas le statut 404) image de la liste de tableaux (dans le répertoire en cours):

<img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)">

Peut-être faut-il l'améliorer, mais:

var srcToInsertArr = ['empty1.png', 'empty2.png', 'needed.png', 'notActual.png']; // try to insert one by one img from this array
    var path;
    var imgNotFounded = true; // to mark when success

    var replaceEmptyImage = {
        insertImg: function (elem) {

            if (srcToInsertArr.length == 0) { // if there are no more src to try return
                return "no-image.png";
            }
            if(!/undefined/.test(elem.src)) { // remember path
                path = elem.src.split("/").slice(0, -1).join("/"); // "http://localhost:63342/GetImage"
            }
            var url = path + "/" + srcToInsertArr[0];

            srcToInsertArr.splice(0, 1); // tried 1 src

            
                if(imgNotFounded){ // while not success
                    replaceEmptyImage.getImg(url, path, elem); // CALL GET IMAGE
                }
            

        },
        getImg: function (src, path, elem) { // GET IMAGE

            if (src && path && elem) { // src = "http://localhost:63342/GetImage/needed.png"
                
                var pathArr = src.split("/"); // ["http:", "", "localhost:63342", "GetImage", "needed.png"]
                var name = pathArr[pathArr.length - 1]; // "needed.png"

                xhr = new XMLHttpRequest();
                xhr.open('GET', src, true);
                xhr.send();

                xhr.onreadystatechange = function () {

                    if (xhr.status == 200) {
                        elem.src = src; // insert correct src
                        imgNotFounded = false; // mark success
                    }
                    else {
                        console.log(name + " doesn't exist!");
                        elem.onerror();
                    }

                }
            }
        }

    };

Donc, il insérera le fichier "needed.png" correct dans mon src ou "no-image.png" à partir du répertoire en cours.

J'ai trouvé ce post en regardant cet autre SO post . Vous trouverez ci-dessous une copie de la réponse que j'ai donnée ici.

Je sais que c'est un vieux fil, mais React est devenu populaire et, peut-être, quelqu'un qui utilise React viendra ici chercher une réponse au même problème.

Donc, si vous utilisez React, vous pouvez faire quelque chose comme ci-dessous, qui était une réponse originale fournie par Ben Alpert de l'équipe React ici

getInitialState: function(event) {
    return {image: "http://example.com/primary_image.jpg"};
},
handleError: function(event) {
    this.setState({image: "http://example.com/failover_image.jpg"});
},
render: function() {
    return (
        <img onError={this.handleError} src={src} />;
    );
}
4
Jordan Bonitatis

jQuery 1.8

// If missing.png is missing, it is replaced by replacement.png
$( "img" )
  .error(function() {
    $( this ).attr( "src", "replacement.png" );
  })
  .attr( "src", "missing.png" );

jQuery 3

// If missing.png is missing, it is replaced by replacement.png
$( "img" )
  .on("error", function() {
    $( this ).attr( "src", "replacement.png" );
  })
  .attr( "src", "missing.png" );

référence

3
Nabi K.A.Z.

J'ai résolu mon problème avec ces deux fonctions simples:

function imgExists(imgPath) {
    var http = jQuery.ajax({
                   type:"HEAD",
                   url: imgPath,
                   async: false
               });
    return http.status != 404;
}

function handleImageError() {
    var imgPath;

    $('img').each(function() {
        imgPath = $(this).attr('src');
        if (!imgExists(imgPath)) {
            $(this).attr('src', 'images/noimage.jpg');
        }
    });
}
3

Je ne sais pas s'il existe un meilleur moyen, mais je peux penser à un bidouillage pour l'obtenir - vous pouvez poster Ajax sur l'URL img et analyser la réponse pour voir si l'image est réellement revenue. Si elle revient comme une 404 ou quelque chose comme ça, échangez l'img. Bien que je m'attende à ce que ce soit assez lent.

3
Chii

Cela me frustre depuis des années. Mon correctif CSS définit une image d’arrière-plan sur le img. Lorsqu'une image dynamique src ne se charge pas au premier plan, un espace réservé est visible sur le bg de img. Ceci fonctionne si vos images ont une taille par défaut (par exemple height, min-height, width et/ou min-width).

Vous verrez l'icône d'image brisée, mais c'est une amélioration. Testé à IE9 avec succès. iOS Safari et Chrome ne montrent même pas une icône cassée.

.dynamicContainer img {
  background: url('/images/placeholder.png');
  background-size: contain;
}

Ajoutez une petite animation pour donner à src le temps de se charger sans scintillement de fond. Chrome s'estompe doucement à l'arrière-plan, mais pas Safari sur le bureau.

.dynamicContainer img {
  background: url('/images/placeholder.png');
  background-size: contain;
  -webkit-animation: fadein 1s;
  animation: fadein 1s;                     
}

@-webkit-keyframes fadein {
  0%   { opacity: 0.0; }
  50%  { opacity: 0.5; }
  100% { opacity: 1.0; }
}

@keyframes fadein {
  0%   { opacity: 0.0; }
  50%  { opacity: 0.5; }
  100% { opacity: 1.0; }
}
2
Dylan Valade

Je pense avoir un moyen plus élégant de déléguer et de capturer des événements sur window 'error même lorsque le chargement de l'image de sauvegarde échoue.

img {
  width: 100px;
  height: 100px;
}
<script>
  window.addEventListener('error', windowErrorCb, {
    capture: true
  }, true)

  function windowErrorCb(event) {
    let target = event.target
    let isImg = target.tagName.toLowerCase() === 'img'
    if (isImg) {
      imgErrorCb()
      return
    }

    function imgErrorCb() {
      let isImgErrorHandled = target.hasAttribute('data-src-error')
      if (!isImgErrorHandled) {
        target.setAttribute('data-src-error', 'handled')
        target.src = 'backup.png'
      } else {
        //anything you want to do
        console.log(target.alt, 'both Origin and backup image fail to load!');
      }
    }
  }
</script>
<img id="img" src="error1.png" alt="error1">
<img id="img" src="error2.png" alt="error2">
<img id="img" src="https://i.stack.imgur.com/ZXCE2.jpg" alt="avatar">

Le point est:

  1. Placez le code dans le head et exécutez-le en tant que premier script en ligne. Donc, il va écouter les erreurs se produisent après le script.

  2. Utilisez la capture d’événements pour détecter les erreurs, en particulier pour les événements qui ne font pas de bulles.

  3. Utilisez la délégation d'événements qui évite de lier des événements sur chaque image.

  4. Attribuez à l'attribut error img un attribut après leur avoir attribué un backup.png pour éviter la disparition de backup.png et la boucle infinie suivante, comme ci-dessous:

img error-> backup.png-> error-> backup.png-> error -> ,

2
xianshenglu

Si l'image ne peut pas être chargée (par exemple, parce qu'elle n'est pas présente dans l'URL fournie), l'URL de l'image sera remplacée par défaut,

Pour plus d'informations sur . Error ()

$('img').on('error', function (e) {
  $(this).attr('src', 'broken.png');
});
2
Casper
;(window.jQuery || window.Zepto).fn.fallback = function (fallback) {
    return this.one('error', function () {
        var self = this;
        this.src = (fallback || 'http://lorempixel.com/$width/$height')
        .replace(/\$(\w+)/g, function (m, t) { return self[t] || ''; });
    });
};

Vous pouvez passer un chemin d’espace réservé et y accéder à toutes les propriétés de l’objet d’image défectueux via $*:

$('img').fallback('http://dummyimage.com/$widthx$height&text=$src');

http://jsfiddle.net/ARTsinn/Cu4Zn/

2
yckart

J'ai le même problème. Ce code fonctionne bien sur mon cas.

// Replace broken images by a default img
$('img').each(function(){
    if($(this).attr('src') === ''){
      this.src = '/default_feature_image.png';
    }
});
1
Dale Nguyen

Parfois, l’utilisation de l’événement error n’est pas réalisable, par exemple. parce que vous essayez de faire quelque chose sur une page déjà chargée, par exemple lorsque vous exécutez du code via la console, un bookmarklet ou un script chargé de manière asynchrone. Dans ce cas, vérifier que img.naturalWidth et img.naturalHeight sont 0 semble correspondre à l'astuce.

Par exemple, voici un extrait permettant de recharger toutes les images brisées de la console:

$$("img").forEach(img => {
  if (!img.naturalWidth && !img.naturalHeight) {
    img.src = img.src;
  }
}
1
Lea Verou

Je trouve que cela fonctionne mieux. Si une image ne parvient pas à se charger la première fois, elle est complètement supprimée du DOM. L'exécution de console.clear() garde la fenêtre de la console propre, car les erreurs 404 ne peuvent pas être omises avec des blocs try/catch.

$('img').one('error', function(err) {
    // console.log(JSON.stringify(err, null, 4))
    $(this).remove()
    console.clear()
})
0
indospace.io