Precaricamento delle immagini con jQuery


689

Sto cercando un modo semplice e veloce per precaricare le immagini con JavaScript. Sto usando jQuery se questo è importante.

L'ho visto qui ( http: //nettuts.com ... ):

function complexLoad(config, fileNames) {
  for (var x = 0; x < fileNames.length; x++) {
    $("<img>").attr({
      id: fileNames[x],
      src: config.imgDir + fileNames[x] + config.imgFormat,
      title: "The " + fileNames[x] + " nebula"
    }).appendTo("#" + config.imgContainer).css({ display: "none" });
  }
};

Ma sembra un po 'esagerato per quello che voglio!

So che ci sono plugin jQuery là fuori che lo fanno, ma sembrano tutti un po 'grandi (in termini di dimensioni); Ho solo bisogno di un modo rapido, semplice e breve per precaricare le immagini!


10
$.each(arguments,function(){(new Image).src=this});
David Hellsing,

Risposte:


969

Veloce e facile:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function(){
        $('<img/>')[0].src = this;
        // Alternatively you could use:
        // (new Image()).src = this;
    });
}

// Usage:

preload([
    'img/imageName.jpg',
    'img/anotherOne.jpg',
    'img/blahblahblah.jpg'
]);

Oppure, se si desidera un plug-in jQuery:

$.fn.preload = function() {
    this.each(function(){
        $('<img/>')[0].src = this;
    });
}

// Usage:

$(['img1.jpg','img2.jpg','img3.jpg']).preload();

25
L'elemento immagine non deve essere inserito nel DOM per assicurarsi che il browser lo memorizzi nella cache?
JoshNaro,

8
Credo $('<img />')che crei solo un elemento immagine in memoria (vedi link ). Sembra che '$('<img src="' + this + '" />')creerebbe effettivamente l'elemento all'interno di un DIV nascosto, perché è più "complicato". Tuttavia, non penso che ciò sia necessario per la maggior parte dei browser.
JoshNaro,

104
Questo è un modo strano di scrivere un plugin jQuery. Perché no $.preload(['img1.jpg', 'img2.jpg'])?
alex

12
Assicurati di chiamarlo all'interno $(window).load(function(){/*preload here*/});perché in questo modo tutte le immagini nel documento vengono caricate per prime, è probabile che siano necessarie per prime.
Jasper Kennis,

12
@RegionalC - Potrebbe essere un po 'più sicuro impostare l' loadevento prima di impostare il srccaso in cui l'immagine termina il caricamento prima che venga impostato l'evento load? $('<img/>').load(function() { /* it's loaded! */ }).attr('src', this);
sparebytes

102

Ecco una versione ottimizzata della prima risposta che carica effettivamente le immagini in DOM e la nasconde per impostazione predefinita.

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img />').attr('src',this).appendTo('body').css('display','none');
    });
}

38
hide()è più conciso di css('display', 'none').
alex,

6
Qual è il vantaggio di inserirli nel DOM?
alex

Vorrei anche sapere il vantaggio di inserirli nel DOM.
jedmao,

11
Dalla mia esperienza, il precaricamento di un'immagine nel DOM rende il browser consapevole della sua esistenza e della sua corretta memorizzazione nella cache. Altrimenti, l'immagine esiste solo nella memoria che funziona solo per le app a pagina singola.
Dennis Rongo,

Dennis Rongo. L'aggiunta di immagini al DOM ha riparato il caricamento casuale su Chrome. Grazie!
tmorell,

52

Usa oggetto immagine JavaScript .

Questa funzione consente di attivare una richiamata dopo aver caricato tutte le immagini. Tuttavia, si noti che non attiverà mai un callback se almeno una risorsa non è caricata. Ciò può essere facilmente risolto implementando il onerrorcallback e incrementando il loadedvalore o gestendo l'errore.

var preloadPictures = function(pictureUrls, callback) {
    var i,
        j,
        loaded = 0;

    for (i = 0, j = pictureUrls.length; i < j; i++) {
        (function (img, src) {
            img.onload = function () {                               
                if (++loaded == pictureUrls.length && callback) {
                    callback();
                }
            };

            // Use the following callback methods to debug
            // in case of an unexpected behavior.
            img.onerror = function () {};
            img.onabort = function () {};

            img.src = src;
        } (new Image(), pictureUrls[i]));
    }
};

preloadPictures(['http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar'], function(){
    console.log('a');
});

preloadPictures(['http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar'], function(){
    console.log('b');
});

4
Fai la cosa giusta, usa l'oggetto Immagine JavaScript. hai visto persone fare la cosa sbagliata in queste risposte?
alex

Codice brillante. Sono corretto nel pensare che questo genererà l' onloadevento anche se l'immagine viene memorizzata nella cache? (Perché img.onloadviene dichiarato per primo). Questo è ciò che i miei test hanno mostrato.
Startec,

3
@alex potenzialmente, sì. Se l'obiettivo è precaricare (il che suggerisce un ordine di prestazioni), preferirei vedere un'opzione JS grezza invece delle opzioni dipendenti da jQuery.
Charlie Schliesser,

Ho adorato questa soluzione ma ho appena scoperto che non funziona nel mio Firefox. Sono solo io o gli altri hanno lo stesso problema?
Gazillion,

@Gazillion fornisce maggiori dettagli. Come definisci "non funzionante"? Qual è la versione FF?
Gajus,

35

JP, Dopo aver verificato la tua soluzione, stavo ancora riscontrando problemi in Firefox in cui non si sarebbe precaricato le immagini prima di spostarsi con il caricamento della pagina. L'ho scoperto inserendone alcuni sleep(5)nel mio script lato server. Ho implementato la seguente soluzione basata sulla tua che sembra risolverla.

Fondamentalmente ho aggiunto un callback al tuo plug-in di precaricamento jQuery, in modo che venga chiamato dopo che tutte le immagini sono state caricate correttamente.

// Helper function, used below.
// Usage: ['img1.jpg','img2.jpg'].remove('img1.jpg');
Array.prototype.remove = function(element) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == element) { this.splice(i,1); }
  }
};

// Usage: $(['img1.jpg','img2.jpg']).preloadImages(function(){ ... });
// Callback function gets called after all images are preloaded
$.fn.preloadImages = function(callback) {
  checklist = this.toArray();
  this.each(function() {
    $('<img>').attr({ src: this }).load(function() {
      checklist.remove($(this).attr('src'));
      if (checklist.length == 0) { callback(); }
    });
  });
};

Per interesse, nel mio contesto, sto usando questo come segue:

$.post('/submit_stuff', { id: 123 }, function(response) {
  $([response.imgsrc1, response.imgsrc2]).preloadImages(function(){
    // Update page with response data
  });
});

Spero che questo aiuti qualcuno che arriva a questa pagina da Google (come ho fatto io) alla ricerca di una soluzione per precaricare le immagini sulle chiamate Ajax.


2
Per coloro che non sono interessati a rovinare Array.prototype, invece, puoi fare: checklist = this.lengthE nella funzione onload: checklist--Quindi:if (checklist == 0) callback();
MiniGod

3
Andrebbe tutto bene, tuttavia l'aggiunta di nuovi o la rimozione di metodi esistenti a un oggetto che non possiedi è una delle peggiori pratiche in JavaScript.
Rihards,

Bello e veloce, ma questo codice non attiverà mai la richiamata se una delle immagini è rotta o impossibile da caricare.
SammyK,

.attr({ src: this }).load(function() {...}).load(function() {...}).attr({ src: this })altrimenti dovrebbe esserci problemi di memorizzazione nella cache.
Kevin B,

25

Questo codice jQuery a una riga crea (e carica) un elemento img DOM senza mostrarlo:

$('<img src="img/1.jpg"/>');

4
@huzzah - Potresti stare meglio usando solo gli sprite. Meno richieste http. :)
Alex K,

22
$.fn.preload = function (callback) {
  var length = this.length;
  var iterator = 0;

  return this.each(function () {
    var self = this;
    var tmp = new Image();

    if (callback) tmp.onload = function () {
      callback.call(self, 100 * ++iterator / length, iterator === length);
    };

    tmp.src = this.src;
  });
};

L'utilizzo è abbastanza semplice:

$('img').preload(function(perc, done) {
  console.log(this, perc, done);
});

http://jsfiddle.net/yckart/ACbTK/


Questa è davvero una buona risposta, dovrebbe davvero essere la risposta più votata imho.
sleepycal,

1
Alcune parole esplicative sarebbero state carine.
Robsch,

Buona risposta, ma suggerisco di usare picsum.photos invece di lorempixel.com
Aleksandar il

19

Ho un piccolo plugin che gestisce questo.

Si chiama waitForImages e può gestire imgelementi o qualsiasi elemento con un riferimento a un'immagine nel CSS, ad es div { background: url(img.png) }.

Se volessi semplicemente caricare tutte le immagini, comprese quelle a cui fa riferimento il CSS, ecco come lo faresti :)

$('body').waitForImages({
    waitForAll: true,
    finished: function() {
       // All images have loaded.
    }  
});

Questo plugin fa sì che le immagini che non sono ancora apparse sulla pagina vengano caricate o allega solo eventi alle immagini che stavano già per essere caricate?
Dave Cameron,

@DaveCameron Non rispetta se le immagini sono visibili o meno. Potresti facilmente fork e apportare quella modifica - basta aggiungere :visibleal selettore personalizzato.
alex

Questo plugin sembra molto interessante. Tuttavia, la documentazione di jquery evidenzia che l' loadevento, quando applicato alle immagini: "non funziona in modo coerente o affidabile su più browser". Come è riuscito il plugin a evitarlo?
EleventyOne,

@EleventyOne Controlla l'origine per quanto riguarda il selettore personalizzato.
alex,

@alex In che modo questo plugin carica le immagini impostate nel CSS su: hover of a element? Non funziona per me
Philipp Hofmann,

13

puoi caricare immagini nel tuo html da qualche parte usando la display:none;regola css , quindi mostrarle quando vuoi con js o jquery

non usare le funzioni js o jquery per precaricare è solo una regola css Vs molte righe di js da eseguire

esempio: HTML

<img src="someimg.png" class="hide" alt=""/>

Css:

.hide{
display:none;
}

jQuery:

//if want to show img 
$('.hide').show();
//if want to hide
$('.hide').hide();

Il precaricamento delle immagini con jquery / javascript non è positivo perché le immagini impiegano pochi millisecondi per caricarsi nella pagina + hai millisecondi per analizzare ed eseguire lo script, specialmente se sono immagini grandi, quindi nasconderle in hml è meglio anche per le prestazioni, perché l'immagine è davvero precaricata senza essere visibile affatto, fino a quando non lo mostri!


2
Maggiori informazioni su questo approccio sono disponibili qui: perishablepress.com/…
gdelfino

3
Ma devi essere consapevole che questa tecnica ha un grosso svantaggio: la tua pagina non verrà caricata completamente fino a quando non verranno caricate tutte le immagini. A seconda del numero di immagini da precaricare e delle loro dimensioni, ciò potrebbe richiedere del tempo. Ancora peggio, se il tag <img> non specifica un'altezza e una larghezza, alcuni browser potrebbero attendere fino al recupero dell'immagine prima di eseguire il rendering del resto della pagina.

@Alex voi in ogni caso necessario caricare l'IMG, siete liberi di scegliere se caricare loro con html e evitare qualsiasi tipo di lampeggiare e le immagini caricate e mezzo, o se si desidera ottenere maggiori velocità in corso per una soluzione non è stabile
itsme

Credo davvero che anche la creazione di tag html con javascript è illeggibile a tutti solo i miei 2 centesimi
itsme

1
Avevo bisogno di una soluzione molto rapida per un progetto molto complesso e questo è tutto.
Germstorm,

13

questo plugin jquery imageLoader è solo 1.39kb

utilizzo:

$({}).imageLoader({
    images: [src1,src2,src3...],
    allcomplete:function(e,ui){
        //images are ready here
        //your code - site.fadeIn() or something like that
    }
});

ci sono anche altre opzioni come se si desidera caricare le immagini in modo sincrono o asincrono e un evento completo per ogni singola immagine.


@AamirAfridi Perché è quello?
Ian

1
@Ian perché il documento è già pronto quando viene attivato il callback. $ (documento). già utilizzato per assicurarsi che il DOM sia caricato. Quando si tratta di richiamata, ciò significa che tutte le immagini sono caricate, il che significa che yoru DOM è caricato, quindi non è necessario alcun documento. Già all'interno di una richiamata.
Aamir Afridi

1
@AamirAfridi Non vi è alcuna garanzia che il documento sia pronto nel callback ... da dove lo deducete? Non c'è nulla nella pagina del plugin che dice che il allcompletecallback viene eseguito dopo che il DOM è pronto. C'è una buona probabilità che le immagini finiscano di caricarsi dopo che il DOM è pronto, ma non c'è motivo di supporre. Non so perché pensi che i callback siano magici e vengano eseguiti dopo che il DOM è pronto ... puoi spiegare da dove lo stai ottenendo? Solo perché le immagini sono caricate non significa che il DOM sia pronto
Ian

@AamirAfridi E anche la documentazione per il plugin dice: NB to use this as an image preloader simply put your $(document).ready(function(){}); into your 'allcomplete' event : > simples!... raccomanda direttamente ciò che mostra questa risposta.
Ian

5
@AamirAfridi Non ha senso per questa situazione. Il plugin è un pre- caricatore. Vuoi eseguirlo il prima possibile. E ci sono molte cose che non dipendono dal DOM che vuoi sparare il prima possibile, e poi quando il DOM è pronto, fai qualcosa.
Ian

9

Un modo rapido e senza plug-in per precaricare le immagini in jQuery e ottenere una funzione di callback è quello di creare più imgtag contemporaneamente e contare le risposte, ad es.

function preload(files, cb) {
    var len = files.length;
    $(files.map(function(f) {
        return '<img src="'+f+'" />';
    }).join('')).load(function () {
        if(--len===0) {
            cb();
        }
    });
}

preload(["one.jpg", "two.png", "three.png"], function() {
    /* Code here is called once all files are loaded. */
});
    

Nota che se vuoi supportare IE7, dovrai usare questa versione leggermente meno carina (che funziona anche con altri browser):

function preload(files, cb) {
    var len = files.length;
    $($.map(files, function(f) {
        return '<img src="'+f+'" />';
    }).join('')).load(function () {
        if(--len===0) {
            cb();
        }
    });
}

7

Grazie per questo! Vorrei aggiungere un piccolo riff alla risposta di JP: non so se questo aiuterà nessuno, ma in questo modo non devi creare una serie di immagini e puoi precaricare tutte le tue immagini di grandi dimensioni se dai un nome corretto ai tuoi pollici. Questo è utile perché ho qualcuno che sta scrivendo tutte le pagine in html e garantisce loro un passo in meno da fare per loro - eliminando la necessità di creare l'array di immagini e un altro passaggio in cui le cose potrebbero essere rovinate.

$("img").each(function(){
    var imgsrc = $(this).attr('src');
    if(imgsrc.match('_th.jpg') || imgsrc.match('_home.jpg')){
      imgsrc = thumbToLarge(imgsrc);
      (new Image()).src = imgsrc;   
    }
});

Fondamentalmente, per ogni immagine sulla pagina prende lo src di ogni immagine, se soddisfa determinati criteri (è un pollice o immagine della home page) cambia il nome (una stringa di base sostituisce nell'immagine src), quindi carica le immagini .

Nel mio caso la pagina era piena di immagini di pollice tutte denominate qualcosa come image_th.jpg e tutte le corrispondenti immagini di grandi dimensioni sono denominate image_lg.jpg. Il pollice in grande sostituisce semplicemente _th.jpg con _lg.jpg e quindi precarica tutte le immagini di grandi dimensioni.

Spero che questo aiuti qualcuno.


3
    jQuery.preloadImage=function(src,onSuccess,onError)
    {
        var img = new Image()
        img.src=src;
        var error=false;
        img.onerror=function(){
            error=true;
            if(onError)onError.call(img);
        }
        if(error==false)    
        setTimeout(function(){
            if(img.height>0&&img.width>0){ 
                if(onSuccess)onSuccess.call(img);
                return img;
            }   else {
                setTimeout(arguments.callee,5);
            }   
        },0);
        return img; 
    }

    jQuery.preloadImages=function(arrayOfImages){
        jQuery.each(arrayOfImages,function(){
            jQuery.preloadImage(this);
        })
    }
 // example   
    jQuery.preloadImage(
        'img/someimage.jpg',
        function(){
            /*complete
            this.width!=0 == true
            */
        },
        function(){
            /*error*/
        }
    )

7
Benvenuto in Stack Overflow! Invece di pubblicare solo un blocco di codice, spiega perché questo codice risolve il problema posto. Senza una spiegazione, questa non è una risposta.
Martijn Pieters

3

Io uso il seguente codice:

$("#myImage").attr("src","img/spinner.gif");

var img = new Image();
$(img).load(function() {
    $("#myImage").attr("src",img.src);
});
img.src = "http://example.com/imageToPreload.jpg";

Associare prima all'evento load, quindi impostare src.
Kevin B,

1

Vorrei utilizzare un file manifest per dire ai browser (moderni) di caricare anche tutte le immagini rilevanti e memorizzarle nella cache. Usa Grunt e grunt-manifest per farlo automaticamente e non preoccuparti mai più di script di precaricamento, invalidatori di cache, CDN ecc.

https://github.com/gunta/grunt-manifest


0

Questo funziona per me anche in IE9:

$('<img src="' + imgURL + '"/>').on('load', function(){ doOnLoadStuff(); });

1
Questo alla fine non riuscirà a causa della memorizzazione nella cache, associare sempre l'evento load prima di impostare l'attributo src.
Kevin B,

0

Volevo farlo con un overlay personalizzato dell'API di Google Maps. Il loro codice di esempio usa semplicemente JS per inserire elementi IMG e la casella segnaposto immagine viene visualizzata fino a quando l'immagine non viene caricata. Ho trovato una risposta qui che ha funzionato per me: https://stackoverflow.com/a/10863680/2095698 .

$('<img src="'+ imgPaht +'">').load(function() {
$(this).width(some).height(some).appendTo('#some_target');
});

Questo precarica un'immagine come suggerito in precedenza, quindi utilizza il gestore per aggiungere l'oggetto img dopo il caricamento dell'URL img. La documentazione di jQuery avverte che le immagini memorizzate nella cache non funzionano bene con questo codice di eventing / handler, ma funziona per me in FireFox e Chrome e non devo preoccuparmi di IE.


Questo non funzionerà bene con le immagini memorizzate nella cache come hai scoperto. la soluzione alternativa è innanzitutto associare l'evento load, quindi impostare l'attributo src.
Kevin B,

-1
function preload(imgs) {
    $(imgs).each(function(index, value) {
        $('<img />').attr('src', value).appendTo('body').css('display', 'none');
    });
}

.attr('src',value) non .attr('src',this)

solo per sottolineare :)


L'ambito thisall'interno del callback a cui viene passato $.eachviene assegnato al valore che viene ripetuto.
Oybek,

? $ (['img1.jpg', 'img2.jpg', 'img3.jpg']) each (funzione (indice, valore) {console.log (valore); // img1.jpg console.log (questo) ; // String {0 = "i", 1 = "m", 2 = "g", altro ...} $ ('<img />'). Attr ('src', this) .appendTo (' body '). css (' display ',' none ');});
Whisher,

Hm. Immagino che tu sia qui. Ad esempio $("div").each(function(i, el){ console.log(el == this);});genera tutti trues; L'iterazione su array sembra comportarsi diversamente.
Oybek,

-2

5 righe in coffeescript

array = ['/img/movie1.png','/img/movie2.png','/img/movie3.png']

$(document).ready ->
  for index, image of array
    img[index] = new Image()
    img[index].src = image

2
Puoi espandere il funzionamento della soluzione per risolvere la domanda nel PO? E forse commentare il tuo codice in modo che altri possano capirlo più facilmente?
Ro Yo Mi

-4

Per coloro che conoscono un po 'di ActionScript, puoi verificare la presenza di Flash Player, con il minimo sforzo, e creare un preloader flash, che puoi anche esportare in html5 / Javascript / Jquery. Per utilizzarlo se il flash player non viene rilevato, consulta gli esempi su come eseguire questa operazione con il ruolo di YouTube su html5 player :) E creane uno tuo. Non ho i dettagli, perché non ho ancora iniziato, se non dimentico, lo pubblicherò più tardi e proverò un codice Jquery standerd nel mio.


Questa non è una soluzione. Il browser non supporta Flash Player per impostazione predefinita. Può essere facilmente raggiunto con JavaScript, che è la lingua del browser nativo.
Usman Ahmed,

Ricordo gli odiatori di Flash del 2012 ... non era normale ... ovunque andassi ero attaccato quando usavo persino la parola Flash.
Peter Gruppelaar,
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.