it-swarm-eu.dev

jQuery / JavaScript per sostituire le immagini rotte

Ho una pagina web che include un sacco di immagini. A volte l'immagine non è disponibile, quindi un'immagine difettosa viene visualizzata nel browser del client.

Come posso usare jQuery per ottenere il set di immagini, filtrarlo in immagini spezzate e sostituire lo src?


- Ho pensato che sarebbe stato più semplice farlo con jQuery, ma è risultato molto più semplice usare semplicemente una soluzione JavaScript pura, ovvero quella fornita da Prestaul.

516
Dan Lord

Gestisci l'evento onError per l'immagine per riassegnarne l'origine utilizzando JavaScript:

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

O senza una funzione JavaScript:

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

La seguente tabella di compatibilità elenca i browser che supportano la funzione di errore:

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

714
Prestaul

Uso il gestore error integrato:

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

Modifica: Il metodo error() è deprecato in 1.8 e versioni successive. Invece, dovresti usare .on("error") invece:

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

Nel caso qualcuno come me, prova ad associare l'evento error a un tag img HTML dinamico, vorrei sottolineare che c'è un problema:

A quanto pare, gli eventi di errore imgnon creano bolle nella maggior parte dei browser, contrariamente a ciò che standard dice.

Quindi, qualcosa come il seguente non funziona :

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

Spero che questo sarà utile a qualcun altro. Vorrei aver visto questo qui in questo thread. Ma non l'ho fatto. Quindi, lo sto aggiungendo

114
mouad

Ecco una soluzione autonoma:

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

Credo che questo sia quello che stai cercando: jQuery.Preload

Ecco il codice di esempio della demo, specifichi il caricamento e non trovi le immagini e sei tutto pronto:

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

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

23
Mohamad

Ecco un modo rapido e sporco per sostituire tutte le immagini rotte e non è necessario modificare il codice HTML;)

esempio di codepen

    $("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

Mentre l'OP stava cercando di sostituire l'SRC, sono sicuro che molte persone che hanno risposto a questa domanda potrebbero voler solo nascondere l'immagine spezzata, nel qual caso questa semplice soluzione ha funzionato alla grande per me:

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

Non sono riuscito a trovare uno script adatto alle mie esigenze, quindi ho eseguito una funzione ricorsiva per verificare la presenza di immagini rotte e tentare di ricaricarle ogni quattro secondi finché non vengono riparate.

L'ho limitato a 10 tentativi come se non fosse caricato da allora l'immagine potrebbe non essere presente sul server e la funzione entrerebbe in un ciclo infinito. Sto ancora testando però. Sentiti libero di modificarlo :)

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

Questa è una tecnica schifosa, ma è praticamente garantita:

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

Questo è JavaScript, dovrebbe essere compatibile con più browser e fornisce senza il brutto markup 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

Puoi utilizzare il recupero di GitHub per questo:

Frontend: https://github.com/github/fetch
o per Backend, una versione di Node.js: https://github.com/bitinn/node-fetch

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

Modifica: questo metodo sostituirà XHR e apparentemente è già stato in Chrome. A chiunque legga questo in futuro, potrebbe non essere necessario includere la suddetta libreria.

5
BarryMode

Se hai inserito img con innerHTML, come: $("div").innerHTML = <img src="wrong-uri">, puoi caricare un'altra immagine se fallisce, ad es.

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

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

Perché javascript: _needed? Poiché gli script iniettati nel DOM tramite i tag di script in innerHTML non vengono eseguiti al momento della loro immissione, quindi devi essere esplicito.

4
horro

Ecco un esempio che utilizza l'oggetto Image HTML5 avvolto da JQuery. Chiamare la funzione di caricamento per l'URL dell'immagine principale e se tale carico causa un errore, sostituire l'attributo src dell'immagine con un URL di backup.

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

Ho creato un violino per sostituire l'immagine rotta utilizzando l'evento "onerror". Questo potrebbe aiutarti.

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

Usando la risposta di Prestaul , ho aggiunto alcuni assegni e preferisco usare il modo 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

Meglio chiamare usando

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

Perché l'uso di document.ready non richiede necessariamente che le immagini vengano caricate, solo l'HTML. Quindi, non c'è bisogno di una chiamata ritardata.

4
Shade

CoffeeScript variante:

L'ho fatto per risolvere un problema con Turbolinks che a volte causa il metodo .error () in Firefox, anche se l'immagine è davvero lì.

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

JS puro. Il mio compito era: se l'immagine 'bl-once.png' è vuota -> inserisci la prima immagine (che non ha lo stato 404) dall'elenco di array (nella directory corrente):

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

Forse ha bisogno di essere migliorato, ma:

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

                }
            }
        }

    };

Quindi, inserirà correttamente 'needed.png' nel mio src o 'no-image.png' dalla directory corrente.

Ho trovato questo post mentre guardavo quest'altro SO post . Qui sotto c'è una copia della risposta che ho dato lì.

So che questo è un vecchio thread, ma React è diventato popolare e, forse, qualcuno che usa React verrà qui cercando una risposta allo stesso problema.

Quindi, se stai usando React, puoi fare qualcosa di simile al seguente, che era una risposta originale fornita da Ben Alpert del team React qui

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

di riferimento

3
Nabi K.A.Z.

Ho risolto il mio problema con queste due semplici funzioni:

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

Non sono sicuro che ci sia un modo migliore, ma posso pensare a un trucco per ottenerlo - potresti postare Ajax sull'URL img e analizzare la risposta per vedere se l'immagine è effettivamente tornata. Se è tornato come 404 o qualcosa del genere, quindi scambiare il img. Anche se mi aspetto che questo sia piuttosto lento.

3
Chii

Questo mi ha frustrato per anni. La mia correzione CSS imposta un'immagine di sfondo su img. Quando un'immagine dinamica src non viene caricata in primo piano, un segnaposto è visibile sul img 's bg. Questo funziona se le tue immagini hanno una dimensione predefinita (ad esempio height, min-height, width e/o min-width).

Vedrai l'icona dell'immagine spezzata ma è un miglioramento. Testato fino a IE9 con successo. iOS Safari e Chrome non mostrano nemmeno un'icona spezzata.

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

Aggiungi una piccola animazione per dare a src il tempo di caricare senza uno sfarfallio di sfondo. Chrome si dissolve in background senza problemi, ma Safari desktop no.

.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

Penso di avere un modo più elegante con la delega degli eventi e la cattura degli eventi su windowerror anche quando l'immagine di backup non viene caricata.

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

Il punto è :

  1. Inserisci il codice in head ed eseguito come primo script inline. Quindi ascolterà gli errori accaduti dopo la sceneggiatura.

  2. Usa la cattura degli eventi per catturare gli errori, specialmente per quegli eventi che non hanno bolle.

  3. Utilizza la delega degli eventi che evita gli eventi di associazione su ciascuna immagine.

  4. Dare l'errore img element un attributo dopo aver dato loro un backup.png per evitare la scomparsa del backup.png e del successivo ciclo infinito come di seguito:

errore img-> backup.png-> errore-> backup.png-> errore -> ,

2
xianshenglu

Se l'immagine non può essere caricata (ad esempio, poiché non è presente nell'URL fornito), l'URL dell'immagine verrà modificato come predefinito,

Per ulteriori informazioni su . Error ()

$('img').on('error', function (e) {
  $(this).attr('src', 'broken.png');
});
2
CasperSL
;(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] || ''; });
    });
};

È possibile passare un percorso segnaposto e accedere a tutte le proprietà dall'oggetto immagine non riuscito tramite $*:

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

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

2
yckart

Ho avuto lo stesso problema. Questo codice funziona bene sul mio caso.

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

A volte l'utilizzo dell'evento error non è fattibile, ad es. perché stai provando a fare qualcosa su una pagina già caricata, ad esempio quando esegui il codice tramite la console, un bookmarklet o uno script caricato in modo asincrono. In tal caso, controllare che img.naturalWidth e img.naturalHeight siano 0 sembra fare il trucco.

Ad esempio, ecco uno snippet per ricaricare tutte le immagini danneggiate dalla console:

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

Ho trovato che funziona meglio, se una qualsiasi immagine non viene caricata la prima volta, viene completamente rimossa dal DOM. L'esecuzione di console.clear() mantiene la finestra della console pulita, poiché gli errori 404 non possono essere omessi con i blocchi try/catch.

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