Vorladen von Bildern mit jQuery

689

Ich suche nach einer schnellen und einfachen Möglichkeit, Bilder mit JavaScript vorzuladen. Ich benutze jQuery, wenn das wichtig ist.

Ich habe das hier gesehen ( 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" });
  }
};

Aber es sieht ein bisschen übertrieben aus für das, was ich will!

Ich weiß, dass es jQuery-Plugins gibt, die dies tun, aber sie scheinen alle etwas groß (in der Größe) zu sein. Ich brauche nur eine schnelle, einfache und kurze Möglichkeit, Bilder vorzuladen!


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

Antworten:

969

Schnell und einfach:

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

Oder wenn Sie ein jQuery-Plugin möchten:

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

// Usage:

$(['img1.jpg','img2.jpg','img3.jpg']).preload();
James
quelle
25
Muss das Bildelement nicht in das DOM eingefügt werden, um sicherzustellen, dass der Browser es zwischenspeichert?
JoshNaro
8
Ich glaube, es wird $('<img />')nur ein Bildelement im Speicher erstellt (siehe Link ). Es sieht so aus, als '$('<img src="' + this + '" />')würde das Element tatsächlich in einem versteckten DIV erstellt, da es "komplizierter" ist. Ich glaube jedoch nicht, dass dies für die meisten Browser erforderlich ist.
JoshNaro
104
Das ist eine seltsame Art, ein jQuery-Plugin zu schreiben. Warum nicht $.preload(['img1.jpg', 'img2.jpg'])?
Alex
12
Stellen Sie sicher, dass Sie dies im Inneren aufrufen, $(window).load(function(){/*preload here*/});da auf diese Weise alle Bilder im Dokument zuerst geladen werden und sie wahrscheinlich zuerst benötigt werden.
Jasper Kennis
12
@RegionalC - Es kann etwas sicherer sein, das loadEreignis vor dem Festlegen des Ereignisses festzulegen, srcnur für den Fall, dass das Laden des Bildes abgeschlossen ist, bevor das Ladeereignis festgelegt wird. $('<img/>').load(function() { /* it's loaded! */ }).attr('src', this);
Ersatzbytes
102

Hier ist eine optimierte Version der ersten Antwort, die die Bilder tatsächlich in DOM lädt und standardmäßig ausblendet.

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img />').attr('src',this).appendTo('body').css('display','none');
    });
}
Dennis Rongo
quelle
38
hide()ist knapper als css('display', 'none').
Alex
6
Was ist der Vorteil, wenn Sie sie in das DOM einfügen?
alex
Ich würde auch gerne wissen, welchen Vorteil es hat, sie in das DOM einzufügen.
jedmao
11
Nach meiner Erfahrung macht das Vorladen eines Bildes in das DOM den Browser auf seine Existenz aufmerksam und darauf, dass es ordnungsgemäß zwischengespeichert wird. Andernfalls ist das Bild nur im Speicher vorhanden, der nur für Apps mit nur einer Seite funktioniert.
Dennis Rongo
Dennis Rongo. Durch das Anhängen von Bildern an das DOM wurde das zufällige erneute Laden in Chrome behoben. Vielen Dank!
Tmorell
52

Verwenden Sie ein JavaScript- Bildobjekt .

Mit dieser Funktion können Sie beim Laden aller Bilder einen Rückruf auslösen. Beachten Sie jedoch, dass niemals ein Rückruf ausgelöst wird, wenn mindestens eine Ressource nicht geladen ist. Dies kann leicht behoben werden, indem ein onerrorRückruf implementiert und der loadedWert erhöht oder der Fehler behandelt wird.

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');
});
Gajus
quelle
4
Machen Sie das Richtige, verwenden Sie das JavaScript Image-Objekt. Haben Sie beobachtet, dass Menschen in diesen Antworten das Falsche getan haben?
Alex
Genialer Code. Habe ich Recht, onloadwenn ich denke, dass dies das Ereignis auslöst, selbst wenn das Bild zwischengespeichert wird? (Weil img.onloadzuerst deklariert wird). Das haben meine Tests gezeigt.
Startec
3
@alex möglicherweise, ja. Wenn das Ziel das Vorladen ist (was auf eine Reihenfolge der Leistung hindeutet), würde ich es vorziehen, eine unformatierte JS-Option anstelle von jQuery-abhängigen Optionen zu sehen.
Charlie Schliesser
Ich habe diese Lösung geliebt, aber ich habe gerade festgestellt, dass sie in meinem Firefox nicht funktioniert. Ist es nur ich oder haben andere das gleiche Problem?
Gazillion
@ Gazillion geben mehr Details. Wie definieren Sie "nicht funktionieren"? Was ist die FF-Version?
Gajus
35

JP: Nachdem ich Ihre Lösung überprüft hatte, hatte ich immer noch Probleme in Firefox, bei denen die Bilder nicht vor dem Laden der Seite vorgeladen wurden. Ich habe dies entdeckt, indem ich einige sleep(5)in mein serverseitiges Skript eingefügt habe. Ich habe die folgende Lösung basierend auf Ihrer implementiert, die dies zu lösen scheint.

Grundsätzlich habe ich Ihrem jQuery-Preload-Plugin einen Rückruf hinzugefügt, damit es aufgerufen wird, nachdem alle Bilder ordnungsgemäß geladen wurden.

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

Aus Interesse verwende ich dies in meinem Kontext wie folgt:

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

Hoffentlich hilft dies jemandem, der (wie ich) von Google auf diese Seite kommt, nach einer Lösung für das Vorladen von Bildern bei Ajax-Anrufen zu suchen.

Dave
quelle
2
Für diejenigen, die nicht daran interessiert sind, den Array.prototype durcheinander zu bringen, können Sie stattdessen Folgendes tun: checklist = this.lengthUnd in der Onload-Funktion: checklist--Dann:if (checklist == 0) callback();
MiniGod
3
Alles wäre in Ordnung, aber das Hinzufügen neuer oder das Entfernen vorhandener Methoden zu einem Objekt, das Sie nicht besitzen, ist eine der schlechtesten Methoden in JavaScript.
Rihards
Schön und schnell, aber dieser Code löst niemals den Rückruf aus, wenn eines der Bilder beschädigt ist oder nicht geladen werden kann.
SammyK
.attr({ src: this }).load(function() {...})sollte .load(function() {...}).attr({ src: this })sonst sein, werden Sie Caching-Probleme haben.
Kevin B
25

Dieser einzeilige jQuery-Code erstellt (und lädt) ein DOM-Element img, ohne es anzuzeigen:

$('<img src="img/1.jpg"/>');
rkcell
quelle
4
@huzzah - Vielleicht bist du besser dran, wenn du nur Sprites verwendest. Weniger http-Anfragen. :)
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;
  });
};

Die Verwendung ist recht einfach:

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

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

yckart
quelle
Dies ist eine wirklich gute Antwort, es sollte wirklich die am besten gewählte Antwort imho sein.
Sleepycal
1
Einige erklärende Worte wären nett gewesen.
Robsch
Gute Antwort, aber ich schlage vor, picsum.photos anstelle von lorempixel.com zu verwenden
Aleksandar
19

Ich habe ein kleines Plugin, das das erledigt.

Es heißt waitForImages und kann imgElemente oder jedes Element mit einem Verweis auf ein Bild im CSS verarbeiten, z div { background: url(img.png) }.

Wenn Sie einfach alle Bilder laden möchten, einschließlich derjenigen, auf die im CSS verwiesen wird, gehen Sie wie folgt vor :)

$('body').waitForImages({
    waitForAll: true,
    finished: function() {
       // All images have loaded.
    }  
});
Alex
quelle
Verursacht dieses Plugin das Laden von Bildern, die noch nicht auf der Seite angezeigt wurden, oder hängt es nur Ereignisse an Bilder an, die bereits geladen werden sollten?
Dave Cameron
@ DaveCameron Es wird nicht berücksichtigt, ob die Bilder sichtbar sind oder nicht. Sie können es leicht teilen und diese Änderung vornehmen - fügen Sie es einfach :visibleder benutzerdefinierten Auswahl hinzu.
alex
Dieses Plugin sieht sehr interessant aus. In der jquery-Dokumentation wird jedoch hervorgehoben, dass das loadEreignis, wenn es auf Bilder angewendet wird, "nicht konsistent oder zuverlässig browserübergreifend funktioniert". Wie hat das Plugin das geschafft?
EleventyOne
@EleventyOne Überprüfen Sie die Quelle in Bezug auf die benutzerdefinierte Auswahl.
Alex
@alex Wie lädt dieses Plugin Bilder, die in der CSS on: Hover eines Elements festgelegt sind? Es funktioniert nicht für mich
Philipp Hofmann
13

Sie können Bilder mithilfe der CSS- display:none;Regel irgendwo in Ihr HTML laden und sie dann mit js oder jquery anzeigen, wenn Sie möchten

Verwenden Sie keine js- oder jquery-Funktionen zum Vorladen. Dies ist nur eine CSS-Regel. Es müssen viele Zeilen von js ausgeführt werden

Beispiel: 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();

Das Vorladen von Bildern mit jquery / javascript ist nicht gut, da das Laden von Bildern auf Seite + einige Millisekunden dauert. Sie haben Millisekunden Zeit, um das Skript zu analysieren und auszuführen. Dies gilt insbesondere dann, wenn es sich um große Bilder handelt. Denn das Bild ist wirklich vorinstalliert, ohne überhaupt sichtbar zu sein, bis Sie das zeigen!

da ich bin
quelle
2
Weitere Informationen zu diesem Ansatz finden Sie hier: perishablepress.com/...
gdelfino
3
Sie müssen sich jedoch bewusst sein, dass diese Technik einen großen Nachteil hat: Ihre Seite wird erst vollständig geladen, wenn alle Bilder geladen sind. Abhängig von der Anzahl der vorzuladenden Bilder und ihrer Größe kann dies einige Zeit dauern. Schlimmer noch, wenn das <img> -Tag keine Höhe und Breite angibt, warten einige Browser möglicherweise, bis das Bild abgerufen wird, bevor sie den Rest der Seite rendern.
@Alex Sie müssen das IMG trotzdem laden. Sie können frei wählen, ob Sie es mit HTML laden und blinkende und halb geladene Bilder vermeiden möchten oder ob Sie mehr Geschwindigkeit für eine nicht stabile Lösung
erzielen möchten
Außerdem denke ich wirklich, dass das Erstellen von HTML-Tags mit Javascript überhaupt nicht lesbar ist, nur meine 2 Cent
1.
1
Ich brauchte eine sehr schnelle Lösung für ein sehr komplexes Projekt und das war es.
Germstorm
13

Dieses jquery imageLoader- Plugin ist nur 1,39 KB groß

Verwendungszweck:

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

Es gibt auch andere Optionen, z. B. ob Sie die Bilder synchron oder asychron laden möchten, und ein vollständiges Ereignis für jedes einzelne Bild.

alzclarke
quelle
@AamirAfridi Warum ist das so?
Ian
1
@ Ian, da das Dokument zum Zeitpunkt des Rückrufs bereits fertig ist. $ (document) .ready wird verwendet, um sicherzustellen, dass Ihr DOM geladen ist. Wenn es um den Rückruf geht, bedeutet dies, dass alle Bilder geladen sind, was bedeutet, dass Ihr DOM geladen ist, sodass kein Dokument erforderlich ist. Bereits in einem Rückruf.
Aamir Afridi
1
@AamirAfridi Es gibt keine Garantie dafür, dass das Dokument im Rückruf bereit ist ... woher schließen Sie das? Auf der Seite des Plugins steht nichts, was besagt, dass der allcompleteRückruf ausgeführt wird, nachdem das DOM bereit ist. Es besteht eine ziemlich gute Chance, dass die Bilder nach dem Fertigstellen des DOM vollständig geladen werden, aber es gibt keinen Grund anzunehmen. Ich weiß nicht, warum Sie Rückrufe für magisch halten und ausgeführt werden, nachdem das DOM fertig ist. Können Sie erklären, woher Sie das haben? Nur weil die Bilder geladen sind, heißt das nicht, dass das DOM bereit ist
Ian
@AamirAfridi Und die Dokumentation für das Plugin sagt sogar: NB to use this as an image preloader simply put your $(document).ready(function(){}); into your 'allcomplete' event : > simples!... es wird direkt empfohlen, was diese Antwort zeigt.
Ian
5
@AamirAfridi Das macht für diese Situation keinen Sinn. Das Plugin ist ein Pre - Loader. Sie möchten es so schnell wie möglich ausführen. Und es gibt viele Dinge , die auf dem DOM nicht abhängen , dass Sie so schnell wie möglich zu einem Brand werden sollen, und dann , wenn das DOM bereit ist, etwas zu tun.
Ian
9

Eine schnelle, Plugin-freie Möglichkeit, Bilder in jQuery vorzuladen und eine Rückruffunktion zu erhalten, besteht darin, mehrere imgTags gleichzeitig zu erstellen und die Antworten zu zählen, z

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

Beachten Sie, dass Sie, wenn Sie IE7 unterstützen möchten, diese etwas weniger hübsche Version verwenden müssen (die auch in anderen Browsern funktioniert):

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

Danke dafür! Ich würde gerne ein kleines Riff zur Antwort des JP hinzufügen - ich weiß nicht, ob dies jemandem helfen wird, aber auf diese Weise müssen Sie keine Reihe von Bildern erstellen, und Sie können alle Ihre großen Bilder vorab laden, wenn Sie dies tun Benennen Sie Ihre Daumen richtig. Dies ist praktisch, weil ich jemanden habe, der alle Seiten in HTML schreibt, und es stellt sicher, dass sie einen Schritt weniger tun müssen - das Erstellen des Bildarrays entfällt und ein weiterer Schritt, bei dem Dinge durcheinander geraten könnten.

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

Grundsätzlich erfasst es für jedes Bild auf der Seite den Quellcode jedes Bildes. Wenn es bestimmten Kriterien entspricht (ist ein Daumen oder ein Bild auf der Startseite), ändert es den Namen (eine grundlegende Zeichenfolge, die im Bild-Quellcode ersetzt wird) und lädt dann die Bilder .

In meinem Fall war die Seite voller Daumenbilder mit dem Namen image_th.jpg, und alle entsprechenden großen Bilder haben den Namen image_lg.jpg. Der zu große Daumen ersetzt nur das _th.jpg durch _lg.jpg und lädt dann alle großen Bilder vor.

Hoffe das hilft jemandem.

dgig
quelle
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*/
        }
    )
Alex
quelle
7
Willkommen bei Stack Overflow! Erklären Sie bitte , warum dieser Code das aufgeworfene Problem löst , anstatt nur einen Codeblock zu veröffentlichen . Ohne eine Erklärung ist dies keine Antwort.
Martijn Pieters
3

Ich benutze den folgenden Code:

$("#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";
Cristan
quelle
Binden Sie zuerst an das Ladeereignis und setzen Sie dann den src.
Kevin B
1

Ich würde eine Manifest-Datei verwenden, um (modernen) Webbrowsern mitzuteilen, dass sie auch alle relevanten Bilder laden und zwischenspeichern sollen. Verwenden Sie Grunt und Grunt-Manifest, um dies automatisch zu tun, und sorgen Sie sich nie wieder um Preload-Skripte, Cache-Invalidatoren, CDN usw.

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

Christian Landgren
quelle
0

Das funktioniert bei mir sogar in IE9:

$('<img src="' + imgURL + '"/>').on('load', function(){ doOnLoadStuff(); });
Zymotik
quelle
1
Dies schlägt schließlich aufgrund von Caching fehl. Binden Sie immer das Ladeereignis, bevor Sie das src-Attribut festlegen.
Kevin B
0

Ich wollte dies mit einem benutzerdefinierten Overlay der Google Maps-API tun. Ihr Beispielcode verwendet einfach JS, um IMG-Elemente einzufügen, und das Bildplatzhalterfeld wird angezeigt, bis das Bild geladen wird. Ich habe hier eine Antwort gefunden, die für mich funktioniert hat: https://stackoverflow.com/a/10863680/2095698 .

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

Dadurch wird ein Bild wie zuvor vorgeschlagen vorgeladen und anschließend mit dem Handler das img-Objekt angehängt, nachdem die img-URL geladen wurde. Die Dokumentation von jQuery warnt davor, dass zwischengespeicherte Bilder mit diesem Eventing- / Handler-Code nicht gut funktionieren, aber es funktioniert für mich in FireFox und Chrome, und ich muss mir keine Sorgen um den Internet Explorer machen.

bwinchester
quelle
Dies funktioniert nicht gut mit zwischengespeicherten Bildern, wie Sie herausgefunden haben. Die Problemumgehung besteht darin, zuerst das Ladeereignis zu binden und dann das src-Attribut festzulegen.
Kevin B
-1
function preload(imgs) {
    $(imgs).each(function(index, value) {
        $('<img />').attr('src', value).appendTo('body').css('display', 'none');
    });
}

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

nur um darauf hinzuweisen :)

Whisher
quelle
Der Bereich thisinnerhalb des Rückrufs, an den übergeben wird, $.eachwird dem Wert zugewiesen, der iteriert wird.
Oybek
? $ (['img1.jpg', 'img2.jpg', 'img3.jpg']). each (Funktion (Index, Wert) {console.log (Wert); // img1.jpg console.log (this) ; // String {0 = "i", 1 = "m", 2 = "g", mehr ...} $ ('<img />'). Attr ('src', this) .appendTo (' body '). css (' display ',' none ');});
Whisher
Hm. Ich denke du bist hier richtig. $("div").each(function(i, el){ console.log(el == this);});Erzeugt zum Beispiel alle trues; Die Iteration über das Array scheint sich anders zu verhalten.
Oybek
-2

5 Zeilen 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
Guy Morita
quelle
2
Können Sie erläutern, wie die Lösung zur Lösung der Frage im OP funktioniert? Und möglicherweise Ihren Code kommentieren, damit andere ihn leichter verstehen können?
Ro Yo Mi
-4

Für diejenigen, die ein wenig ActionScript kennen, können Sie mit minimalem Aufwand nach Flash Player suchen und einen Flash Preloader erstellen, den Sie auch nach HTML5 / Javascript / Jquery exportieren können. Um zu verwenden, ob der Flash-Player nicht erkannt wird, überprüfen Sie Beispiele, wie dies mit der YouTube-Rolle zurück zum HTML5-Player gemacht wird :) Und erstellen Sie Ihren eigenen. Ich habe keine Details, da ich noch nicht angefangen habe. Wenn ich es nicht vergessen habe, werde ich es später veröffentlichen und werde einen Standard-JQuery-Code für meinen ausprobieren.

Peter Gruppelaar
quelle
Dies ist keine Lösung. Der Browser unterstützt Flash Player standardmäßig nicht. Dies kann leicht mit JavaScript erreicht werden, der Muttersprache des Browsers.
Usman Ahmed
Ich erinnere mich an die Flash-Hasser von 2012 ... es war nicht normal ... überall wurde ich angegriffen, als ich sogar das Wort Flash benutzte.
Peter Gruppelaar