Controlla se un'immagine è stata caricata (nessun errore) con jQuery


224

Sto usando JavaScript con la libreria jQuery per manipolare le miniature delle immagini contenute in un elenco non ordinato. Quando l'immagine viene caricata fa una cosa, quando si verifica un errore fa un'altra cosa. Sto usando jQuery load()e error()metodi come eventi. Dopo questi eventi, controllo l'elemento DOM immagine per il .complete per assicurarmi che l'immagine non sia già stata caricata prima che jQuery possa registrare gli eventi.

Funziona correttamente tranne quando si verifica un errore prima che jQuery possa registrare gli eventi. L'unica soluzione a cui riesco a pensare è quella di utilizzare l' onerrorattributo img per memorizzare una "bandiera" da qualche parte a livello globale (o sul nodo stesso) che dice che non è riuscita, quindi jQuery può verificare che "store / node" quando controlli .complete.

Qualcuno ha una soluzione migliore?

Modifica: punti principali in grassetto e ulteriori dettagli aggiunti di seguito: sto verificando se un'immagine è completa (ovvero caricata) DOPO aver aggiunto un evento di caricamento ed errore sull'immagine. In questo modo, se l'immagine è stata caricata prima che gli eventi fossero registrati, lo saprò ancora. Se l'immagine non viene caricata dopo gli eventi, gli eventi se ne occuperanno. Il problema è che posso facilmente verificare se un'immagine è già stata caricata, ma non posso dire se si è verificato invece un errore.


Quando registri gli eventi jQuery? Forse alcuni codici aiuteranno. :)
okw il

C'è molto codice, quello che ho detto sopra è solo una versione molto semplice di quello che sto facendo. Chiamo gli eventi dopo che il DOM è stato caricato, viene chiamato un metodo per aggiungere eventi alle anteprime.
William,

Risposte:


250

Un'altra opzione è quella di attivare gli eventi onloade / o onerrorcreando un elemento immagine in memoria e impostando il suo srcattributo srcsull'attributo originale dell'immagine originale. Ecco un esempio di cosa intendo:

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

Spero che questo ti aiuti!


27
Non sembra funzionare come speravo. In Google Chrome sembra che ci siano problemi quando l'immagine è già nella cache. Non attiva il metodo load (). :(
William,

4
Ugg, hai ragione. Chrome è sicuramente il browser più fastidioso per cui sviluppare. Sul luminoso, penso di aver trovato un modo per aggirare: imposta la sorgente dell'immagine su "", quindi torna alla fonte originale. Aggiornerò la mia risposta.
Xavi il

1
Dovresti inserire la .attrriga dopo le righe .loade .error. Altrimenti si rischia che l'immagine possa essere caricata (o che si verifichi un errore) prima che vengano aggiunti quei callback e questi non verranno chiamati.
callum

19
@Xavi Chrome non è il browser più fastidioso per cui sviluppare, prova a sviluppare per Internet Explorer 7 o meno. Oltre ad aggiungere un parametro $ _GET al caricamento dell'immagine, caricherà una nuova immagine ogni volta, come suggerito da Gromix.
SSH Questo

10
I .load()e .error()metodi sono confuse e ora deprecati, uso .on()e utilizzare i loade errorcome eventi.
Firsh - LetsWP.io

235

Controllare le proprietà completee naturalWidth, in questo ordine.

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
Interessante, stavo guardando quel post prima e non mi rendevo conto che lo stavano facendo! completo per IE in quanto naturalWidth non è definito in IE. Vado a controllarlo ora.
William, il

3
Apparentemente, questo funziona in modo affidabile solo la prima volta. Se poi modifichi l'src dell'immagine, almeno Safari Mobile continuerà a riportare il primo valore sia per naturalWidth sia per complete.
giorgiano

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

5
@vsync probabilmente vorresti usarlo come controllo una tantum, e se l'immagine non è ancora stata caricata, imposta un gestore di eventi "load". Non dovrebbe essere necessario martellare la CPU eseguendo questo controllo più volte.
Michael Martin-Smucker,

2
Per i curiosi, questo è esattamente ciò che fa la libreria imagesLoaded collegata di seguito. Quindi, per un utilizzo unico,
provalo

57

Sulla base della mia comprensione della specifica HTML W3C per l' imgelemento , dovresti essere in grado di farlo utilizzando una combinazione degli attributi completee naturalHeight, in questo modo:

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

Dalla specifica per l' completeattributo:

L'attributo IDL completo deve restituire true se si verifica una delle seguenti condizioni:

  • L'attributo src è omesso.
  • L'attività finale accodata dall'origine dell'attività di rete una volta recuperata la risorsa è stata messa in coda.
  • L'elemento img è completamente disponibile.
  • L'elemento img è rotto.

Altrimenti, l'attributo deve restituire false.

Quindi, in sostanza, completerestituisce true se l'immagine ha terminato il caricamento o non è riuscito a caricarsi. Dal momento che vogliamo solo il caso in cui l'immagine è stata caricata correttamente, dobbiamo controllare anche l' nauturalHeightattributo:

L'IDL attribuisce naturalWidthe naturalHeightdeve restituire la larghezza e l'altezza intrinseca dell'immagine, in pixel CSS, se l'immagine è disponibile, oppure 0.

E availablesi definisce così:

Un img è sempre in uno dei seguenti stati:

  • Non disponibile : l'agente utente non ha ottenuto alcun dato immagine.
  • Parzialmente disponibile : l'agente utente ha ottenuto alcuni dei dati dell'immagine.
  • Completamente disponibile : l'agente utente ha ottenuto tutti i dati dell'immagine e sono disponibili almeno le dimensioni dell'immagine.
  • Rotto : l'agente utente ha ottenuto tutti i dati immagine che può, ma non può nemmeno decodificare l'immagine abbastanza per ottenere le dimensioni dell'immagine (ad es. L'immagine è corrotta o il formato non è supportato o non è stato possibile ottenere dati) .

Quando un elemento img è nello stato parzialmente disponibile o nello stato completamente disponibile, si dice che sia disponibile.

Quindi se l'immagine è "rotta" (impossibile caricarla), sarà nello stato rotto, non nello stato disponibile, quindi naturalHeightsarà 0.

Pertanto, il controllo imgElement.complete && imgElement.naturalHeight !== 0dovrebbe dirci se l'immagine è stata caricata correttamente.

Puoi leggere ulteriori informazioni al riguardo nelle Specifiche HTML W3C per l' imgelemento o su MDN .


1
Non funziona se l'immagine è caricata con lo stile "content: url"
deathangel908

1
Questo non sembra funzionare in Firefox con immagini SVG dato che il browser riporta l'altezza / larghezza naturale pari a 0. Bug pertinente: bugzilla.mozilla.org/show_bug.cgi?id=1328124
leeb

20

Ho provato molti modi diversi e questo è l'unico che ha funzionato per me

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

È inoltre possibile aggiungere una funzione di richiamata attivata dopo che tutte le immagini sono state caricate nel DOM e pronte. Questo vale anche per le immagini aggiunte dinamicamente. http://jsfiddle.net/kalmarsh80/nrAPk/


collegamento jsfiddle interrotto
Alex Karshin

1
Ho testato le letture interessanti sopra e falliscono tra i test memorizzati nella cache / non memorizzati su una manciata di browser comuni. Questa risposta è simile a un'altra ma è quella che ho implementato e testato proprio ora, posso confermare che funziona su: 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. Non dimenticare di usare addEventListener / removeEventListener: D
danjah

13

Usa la imagesLoadedlibreria javascript .

Utilizzabile con Javascript semplice e come plugin jQuery.

Caratteristiche:

risorse


Ha funzionato perfettamente per me. funzione checkImages (imgs) {$ (imgs) .each (function () {$ (imgs) .imagesLoaded () .progress (function (istanza, immagine) {if (image.isLoaded == false) {console.log (image .img.src + 'impossibile trovare.'); image.img.src = "/templates/img/no-image.jpg";}});}); }
Rooster242

1
sembra avere tonnellate di problemi aperti quali gravi bug, e lo sviluppatore non sembra fare molto al passo con loro. a partire da ora, questo è totalmente inutilizzabile in un ambiente di produzione.
vsync,

3
@vsync Hai letto alcuni dei problemi aperti? Risponde a quasi tutti, e la maggior parte sembra essere un caso irripetibile che pochi altri incontrano. Non ho mai avuto problemi con esso in produzione.
Josh Harrison,

1
si lo uso da solo e a volte non funziona, quindi uso un setTimeout per coprire i casi in cui fallisce
vsync

Ci sono buoni motivi per cui si desidera utilizzare il plug-in imagesLoaded: la completeproprietà non sembra essere chiaramente supportata: impossibile trovare una fonte affidabile di informazioni sul supporto del browser. completeinoltre la proprietà non sembra avere specifiche chiare: la specifica HTML5 è l'unica che la menziona ed è ancora in una versione bozza al momento della scrittura. Se usi naturalWidthe naturalHeighthai solo il supporto IE9 +, quindi se lo usi per scoprire se l'immagine è caricata, hai bisogno di qualche trucco "intelligente" per farlo funzionare su vecchi browser e devi verificare che il comportamento tra browser sia coerente
Adrien essere

8

Recupera informazioni dagli elementi dell'immagine nella pagina
Test di lavoro su Chrome e Firefox
Working jsFiddle (apri la console per vedere il risultato)

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

});

Nota: ho usato jQuery , ho pensato che questo potesse essere doloroso su javascript completo

Trovo buone informazioni qui OpenClassRoom -> questo è un forum francese


3

Rilevatore di rete in tempo reale - controlla lo stato della rete senza aggiornare la pagina: (non è jquery, ma testato e funziona al 100%: (testato su Firefox v25.0))

Codice:

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

in caso di perdita di connessione, premere il pulsante Again.

Aggiornamento 1: Rilevamento automatico senza aggiornare la pagina:

<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%! Cosa succede se il collegamento dell'immagine è bloccato da un proxy / firewall o il server immagine non risponde? La rete funziona ancora :)
Sen Jacob

Questo caricherà di nuovo ogni immagine dal server, eliminando la cache (intenzionalmente). Quindi, solo per il controllo, stai (almeno) raddoppiando la larghezza di banda per tutte le tue immagini. Inoltre, controlla solo se l'immagine esiste sul server, non se è stata caricata in un luogo specifico. Inoltre non c'è modo di sapere quando viene caricata ogni immagine.
Marius Balčytis,

3

Dopo aver letto le interessanti soluzioni in questa pagina, ho creato una soluzione di facile utilizzo fortemente influenzata dal post di SLaks e Noyo che sembra funzionare su versioni piuttosto recenti (al momento della scrittura) di Chrome, IE, Firefox, Safari e Opera (tutto su Windows). Inoltre, ha funzionato su un emulatore iPhone / iPad che ho usato.

Una delle principali differenze tra questa soluzione e SLaks e il post di Noyo è che questa soluzione controlla principalmente le proprietà naturalWidth e naturalHeight. Ho scoperto che nelle attuali versioni del browser, queste due proprietà sembrano fornire i risultati più utili e coerenti.

Questo codice restituisce VERO quando un'immagine è stata caricata completamente E correttamente. Restituisce FALSE quando un'immagine non è stata ancora caricata completamente oppure non è stata caricata correttamente.

Una cosa di cui devi essere consapevole è che questa funzione restituirà anche FALSE se l'immagine è un'immagine di 0x0 pixel. Ma quelle immagini sono abbastanza rare, e non riesco a pensare a un caso molto utile in cui vorresti vedere se un'immagine di pixel 0x0 è stata ancora caricata :)

Innanzitutto alleghiamo una nuova funzione chiamata "isLoaded" al prototipo HTMLImageElement, in modo che la funzione possa essere utilizzata su qualsiasi elemento immagine.

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;

};

Quindi, ogni volta che dobbiamo controllare lo stato di caricamento dell'immagine, chiamiamo semplicemente la funzione "isLoaded".

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

Per il commento di Giorgio sul post di SLaks e Noyo, questa soluzione probabilmente può essere utilizzata come controllo una tantum su Safari Mobile se si prevede di modificare l'attributo SRC. Ma puoi aggirare ciò creando un elemento immagine con un nuovo attributo SRC invece di modificare l'attributo SRC su un elemento immagine esistente.


2

È così che l'ho fatto funzionare su più browser usando una combinazione dei metodi sopra (avevo anche bisogno di inserire immagini dinamicamente nel dom):

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

Nota: sarà necessario fornire uno stato booleano valido per la variabile isIE.


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

// O come plugin

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

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

1

Da quanto ho capito, la proprietà .complete non è standard. Potrebbe non essere universale ... Ho notato che sembra funzionare diversamente in Firefox versi IE. Sto caricando un numero di immagini in javascript, quindi controllo se completo. In Firefox, questo sembra funzionare alla grande. In IE, ciò non accade perché le immagini sembrano caricarsi su un altro thread. Funziona solo se inserisco un ritardo tra la mia assegnazione a image.src e quando controllo la proprietà image.complete.

Anche usare image.onload e image.onerror non funziona per me, perché devo passare un parametro per sapere di quale immagine sto parlando quando viene chiamata la funzione. Qualsiasi modo per farlo sembra fallire perché in realtà sembra passare la stessa funzione, non diverse istanze della stessa funzione. Quindi il valore che ci passo per identificare l'immagine finisce sempre per essere l'ultimo valore nel loop. Non riesco a pensare ad alcun modo per aggirare questo problema.

Su Safari e Chrome, vedo image.complete true e naturalWidth impostati anche quando la console degli errori mostra un 404 per quell'immagine ... e ho rimosso intenzionalmente quell'immagine per testarlo. Ma quanto sopra funziona bene per Firefox e IE.


Hmm, è interessante. Ti dispiacerebbe pubblicare un esempio di codice, quindi voglio provare un paio di cose?
Xavi,

1

Questo frammento di codice mi ha aiutato a risolvere i problemi di memorizzazione nella cache del browser:

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

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

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

Quando la cache del browser è disabilitata, solo questo codice non funziona:

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

per farlo funzionare devi aggiungere:

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

0

Utilizzando questo JavaScriptcodice è possibile verificare che l'immagine sia stata caricata correttamente o meno.

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

Prova questo


0

Ho avuto molti problemi con il caricamento completo di un'immagine e EventListener.

Qualunque cosa abbia provato, i risultati non sono stati affidabili.

Ma poi ho trovato la soluzione. Tecnicamente non è bello, ma ora non ho mai avuto un caricamento di immagine fallito.

Cosa ho fatto:

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

Invece di caricare l'immagine una volta, l'ho appena caricata una seconda volta direttamente dopo la prima volta ed entrambi corro attraverso il gestore degli eventi.

Tutti i miei mal di testa sono spariti!


A proposito: voi ragazzi di StackOverflow mi avete aiutato già più di cento volte. Per questo un grandissimo grazie!


0

Questo ha funzionato bene per me :)

$('.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');
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.