Richiamata jQuery al caricamento dell'immagine (anche quando l'immagine è memorizzata nella cache)


291

Voglio fare:

$("img").bind('load', function() {
  // do stuff
});

Ma l'evento load non si attiva quando l'immagine viene caricata dalla cache. I documenti jQuery suggeriscono un plugin per risolvere questo problema, ma non funziona


12
Dalla tua domanda le cose sono cambiate. Il plug-in rotto è stato spostato in una sintesi e successivamente in un repository con un piccolo plug-in funzionante jQuery.imagesLoaded . Risolvono tutte le piccole stranezze del browser .
Lode

La libreria JQuery sopra menzionata ha funzionato bene per me. Grazie!
entro il

Grazie per il plugin, ha funzionato bene.
onimojo,

Risposte:


572

Se l' srcopzione è già impostata, l'evento viene generato nel caso memorizzato nella cache, prima ancora di ottenere il limite del gestore eventi. Per risolvere questo problema, puoi controllare e attivare l'evento in base al ciclo .complete, in questo modo:

$("img").one("load", function() {
  // do stuff
}).each(function() {
  if(this.complete) {
      $(this).load(); // For jQuery < 3.0 
      // $(this).trigger('load'); // For jQuery >= 3.0 
  }
});

Nota la modifica da .bind()a in .one()modo che il gestore eventi non venga eseguito due volte.


8
La tua soluzione ha funzionato perfettamente per me, ma voglio capire qualcosa, quando verrà eseguito questo codice "if (this.complete)", dopo che il contenuto dell'immagine è stato caricato o prima? perché come posso capire da questo. ogni volta che stai eseguendo il loop su tutti $ ("img") e che il contenuto dell'immagine potrebbe essere vuoto e il caricamento non avverrà. hmmmm, penso che mi manchi qualcosa, sarà bello se riesci a descriverlo per capire meglio. Grazie.
Amr Elgarhy

33
Dalla tua risposta le cose sono cambiate. Ora c'è un piccolo plugin funzionante jQuery.imagesLoaded . Risolvono tutte le piccole stranezze del browser .
Lode

3
Vorrei aggiungere un setTimeout(function(){//do stuff},0)all'interno della funzione 'load' ... lo 0 dà al sistema browser (DOM) un segno di spunta in più per garantire che tutto sia correttamente aggiornato.
dsdsdsdsd,

14
@Lode - è un plugin ENORME, non è affatto piccolo da qualsiasi scala !!
vsync,

5
poiché il metodo JQuery 3 .load()non attiva l'evento e ha 1 argomento richiesto, utilizzare .trigger("load")invece
ForceUser

48

Posso suggerire di ricaricarlo in un oggetto immagine non DOM? Se è memorizzato nella cache, non ci vorrà del tempo e l'onload verrà comunque attivato. Se non è memorizzato nella cache, genererà l'onload al caricamento dell'immagine, che dovrebbe coincidere con il completamento del caricamento della versione DOM dell'immagine.

Javascript:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.src = $('#img').attr('src') ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;
}) ;

Aggiornato (per gestire più immagini e con allegato di caricamento correttamente ordinato):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;

1
Dovresti provare a collegare il loadgestore prima che venga aggiunto, anche questo non funzionerà ma per un'immagine, il codice OP funziona per molti :)
Nick Craver

Grazie, ho aggiunto una versione aggiornata che spero risolva questi due problemi.
Gus,

#imgè un ID, non un selettore di elementi :) this.srcFunziona anche , non è necessario utilizzare jQuery dove non è necessario :) Ma la creazione di un'altra immagine sembra eccessiva in entrambi i casi IMO.
Nick Craver

dovrebbe essere $ ('img'). ma la soluzione è gr8 anche in 2k15
Dimag Kharab,

Inoltre, per il caso di più immagini, se si desidera operare sull'elemento DOM per ciascuna immagine imageLoaded, utilizzaretmp.onload = imageLoaded.bind(this)
blisstdev il

38

La mia soluzione semplice, non ha bisogno di alcun plugin esterno e per i casi comuni dovrebbe essere sufficiente:

/**
 * Trigger a callback when the selected images are loaded:
 * @param {String} selector
 * @param {Function} callback
  */
var onImgLoad = function(selector, callback){
    $(selector).each(function(){
        if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
            callback.apply(this);
        }
        else {
            $(this).on('load', function(){
                callback.apply(this);
            });
        }
    });
};

usalo così:

onImgLoad('img', function(){
    // do stuff
});

ad esempio, per sbiadire le immagini al caricamento puoi fare:

$('img').hide();
onImgLoad('img', function(){
    $(this).fadeIn(700);
});

O in alternativa, se preferisci un approccio simile a un plug-in jquery:

/**
 * Trigger a callback when 'this' image is loaded:
 * @param {Function} callback
 */
(function($){
    $.fn.imgLoad = function(callback) {
        return this.each(function() {
            if (callback) {
                if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
                    callback.apply(this);
                }
                else {
                    $(this).on('load', function(){
                        callback.apply(this);
                    });
                }
            }
        });
    };
})(jQuery);

e usalo in questo modo:

$('img').imgLoad(function(){
    // do stuff
});

per esempio:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});

urm .. e cosa succede se le mie immagini hanno una dimensione impostata con CSS?
Simon_Weaver,

Set width, max-heighte il congedo height:auto, spesso è necessario impostare sia la larghezza e l'altezza solo se è necessario allungare l'immagine; per una soluzione più robusta vorrei utilizzare un plugin come ImagesLoaded
Guari

1
sì, era un errore di digitazione, jsdoc era ok, ho corretto l'esempio di riga
guari

1
Questa soluzione con $ .fn.imgLoad funziona su tutti i browser. Risolvere il problema sarà ancora migliore: && / * per IE 10 - * / this.naturalHeight> 0 Questa linea non prenderà in considerazione lo stile CSS perché img può essere bloccato ma ha altezza. Lavoro in IE10
Patryk Padus,

1
Questo ha una (piccola) condizione di gara. L'immagine può essere caricata in un thread diverso nello script e quindi può essere caricata tra il controllo di complete e il collegamento dell'evento onload, nel qual caso non accadrà nulla. Normalmente JS è sincrono con il rendering e quindi non devi preoccuparti delle condizioni di gara, ma questa è un'eccezione. html.spec.whatwg.org/multipage/…
Mog0

23

Devi davvero farlo con jQuery? Puoi allegare l' onloadevento direttamente anche alla tua immagine;

<img src="/path/to/image.jpg" onload="doStuff(this);" />

Si attiverà ogni volta che l'immagine è stata caricata, dalla cache o meno.


5
È più pulito senza javascript in linea
nocciola

1
Ciao Bjorn, il onloadgestore si attiverà quando l'immagine viene caricata una seconda volta dalla cache?
SexyBeast,

1
@Cupidvogel no non lo farà.
Annunci del

3
Amico, mi hai salvato la vita, ho provato almeno una dozzina di altre soluzioni e la tua è l'unica che ha funzionato. Sto seriamente pensando di creare altri 10 account per votare la tua risposta altre 10 volte. Seriamente grazie!
Carlo,

1
Non ho mai capito l'avversione della gente nei confronti di JS. Il caricamento delle immagini avviene separatamente e fuori sequenza rispetto al resto del processo di caricamento della pagina. Pertanto, questa è l'unica soluzione valida per ottenere un feedback immediato sul completamento del caricamento delle immagini. Tuttavia, se qualcuno deve attendere il caricamento di jQuery e ciò accade in un secondo momento, non dovrà utilizzare la soluzione semplice qui e utilizzare una delle altre soluzioni (quella di Piotr è probabilmente l'opzione migliore poiché non dipende da pseudo- hack ma il controllo altezza () di guari potrebbe essere importante). Anche una coda di elaborazione potrebbe essere utile.
CubicleSoft

16

È inoltre possibile utilizzare questo codice con supporto per errore di caricamento:

$("img").on('load', function() {
  // do stuff on success
})
.on('error', function() {
  // do stuff on smth wrong (error 404, etc.)
})
.each(function() {
    if(this.complete) {
      $(this).load();
    } else if(this.error) {
      $(this).error();
    }
});

1
Questo ha funzionato meglio per me. Penso che il tasto sia impostare loadprima il gestore e poi chiamarlo successivamente nella eachfunzione.
GreenRaccoon23,

impostazione dell'immagine usando il codice sottostante '' var img = new Image (); img.src = sosImgURL; $ (img) .on ("load", function () {''
imdadhusen,

13

Ho avuto questo problema da solo, ho cercato ovunque una soluzione che non prevedesse l'uccisione della mia cache o il download di un plug-in.

Non ho visto subito questa discussione, quindi ho trovato qualcos'altro che è una soluzione interessante e (penso) degno di essere pubblicato qui:

$('.image').load(function(){
    // stuff
}).attr('src', 'new_src');

In realtà ho avuto questa idea dai commenti qui: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

Non ho idea del perché funzioni, ma ho provato questo su IE7 e dove si è rotto prima che ora funzioni.

Spero che sia d'aiuto,

modificare

La risposta accettata in realtà spiega perché:

Se src è già impostato, l'evento viene generato nella cache inserita prima di ottenere il limite del gestore eventi.


4
Ho provato che questo è in molti browser e non l'ho trovato fallire da nessuna parte. Ho usato $image.load(function(){ something(); }).attr('src', $image.attr('src'));per ripristinare la fonte originale.
Maurice,

Ho scoperto che questo approccio non funziona su iOS, almeno per Safari / 601.1 e Safari / 602.1
cronfy

Sarebbe fantastico scoprire perché, in quale browser si trova?
Sammaye,

5

Usando jQuery per generare una nuova immagine con l'src dell'immagine e assegnando il metodo load direttamente a quello, il metodo load viene chiamato con successo quando jQuery termina di generare la nuova immagine. Questo funziona per me in IE 8, 9 e 10

$('<img />', {
    "src": $("#img").attr("src")
}).load(function(){
    // Do something
});

Per quelli che usano Ruby on Rails, con richiesta remota, usando i modelli __rjs.erb, questa è l'unica soluzione che ho trovato. Perché usando i parziali in js.erb, perde de binding ($ ("# img" .on ("load") ... e per le immagini NON è possibile delegare il metodo "on": $ ("body"). on ("load", "# img", function () ...
Albert Català,

5

Una soluzione che ho trovato https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (Questo codice è stato preso direttamente dal commento)

var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;

Questo e 'esattamente quello che stavo cercando. Una singola immagine mi viene dal server. Volevo precaricarlo e poi servire. Non selezionare tutte le immagini come fanno molte risposte. Buona
Kai Qing,

4

Una modifica all'esempio di GUS:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;

tmpImg.src = $('#img').attr('src');
})

Imposta l'origine prima e dopo l'onload.


Come la risposta di @ Gus, questo non funzionerà per più immagini ... e non è necessario impostare srcprima il collegamento del onloadgestore, una volta dopo sarà sufficiente.
Nick Craver

3

Basta aggiungere nuovamente l'argomento src su una riga separata dopo aver definito l'img oject. Ciò indurrà IE a innescare l'evento lad. È brutto, ma è la soluzione più semplice che ho trovato finora.

jQuery('<img/>', {
    src: url,
    id: 'whatever'
})
.load(function() {
})
.appendTo('#someelement');
$('#whatever').attr('src', url); // trigger .load on IE

1

Posso darti un piccolo consiglio se vuoi fare così:

<div style="position:relative;width:100px;height:100px">
     <img src="loading.jpg" style='position:absolute;width:100px;height:100px;z-index:0'/>
     <img onLoad="$(this).fadeIn('normal').siblings('img').fadeOut('normal')" src="picture.jpg" style="display:none;position:absolute;width:100px;height:100px;z-index:1"/>
</div>

Se lo fai quando il browser memorizza le immagini nella cache, non è un problema mostrare sempre img ma caricando img sotto un'immagine reale.


1

Ho avuto questo problema con IE, dove e.target.width sarebbe indefinito. L'evento load si attiva ma non riesco a ottenere le dimensioni dell'immagine in IE (chrome + FF ha funzionato).

Si scopre che è necessario cercare e.currentTarget.naturalWidth e e.currentTarget.naturalHeight .

Ancora una volta, IE fa le cose a modo suo (più complicato).


0

Puoi risolvere il tuo problema usando il plugin JAIL che ti consente anche di caricare le immagini in modo pigro (migliorando le prestazioni della pagina) e passando il callback come parametro

$('img').asynchImageLoader({callback : function(){...}});

L'HTML dovrebbe apparire come

<img name="/global/images/sample1.jpg" src="/global/images/blank.gif" width="width" height="height" />

0

Se vuoi una soluzione CSS pura, questo trucco funziona molto bene: usa l'oggetto di trasformazione. Questo funziona anche con le immagini quando sono memorizzate nella cache o meno:

CSS:

.main_container{
    position: relative;
    width: 500px;
    height: 300px;
    background-color: #cccccc;
}

.center_horizontally{
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: green;
  left: 50%;
  top: 0;
  transform: translate(-50%,0);
}

.center_vertically{
  position: absolute;
  top: 50%;
  left: 0;
  width: 100px;
  height: 100px;
  background-color: blue;
  transform: translate(0,-50%);
}

.center{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  background-color: red;
  transform: translate(-50%,-50%);
}

HTML:

<div class="main_container">
  <div class="center_horizontally"></div>
  <div class="center_vertically"></div>
  <div class="center"></div>
  </div>
</div

Esempio Codepen

Codepen MENO esempio


Potresti dare un esempio di come funziona con il caricamento delle immagini?
Hastig Zusammenstellen,
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.