Prapemuat gambar dengan jQuery

689

Saya mencari cara yang cepat dan mudah untuk memuat foto dengan JavaScript. Saya menggunakan jQuery jika itu penting.

Saya melihat ini di sini ( 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" });
  }
};

Tapi, itu terlihat agak berlebihan untuk apa yang saya inginkan!

Saya tahu ada plugin jQuery di luar sana yang melakukan ini tetapi mereka semua tampak agak besar (dalam ukuran); Saya hanya perlu cara preloading gambar yang cepat, mudah dan singkat!


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

Jawaban:

969

Cepat dan mudah:

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

Atau, jika Anda menginginkan plugin jQuery:

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

// Usage:

$(['img1.jpg','img2.jpg','img3.jpg']).preload();
James
sumber
25
Tidakkah elemen gambar perlu dimasukkan ke DOM untuk memastikan peramban menyimpannya?
JoshNaro
8
Saya percaya $('<img />')hanya menciptakan elemen gambar dalam memori (lihat tautan ). Sepertinya '$('<img src="' + this + '" />')akan benar-benar membuat elemen dalam DIV tersembunyi, karena lebih "rumit". Namun, saya rasa ini tidak diperlukan untuk sebagian besar browser.
JoshNaro
104
Itu adalah cara aneh menulis plugin jQuery. Mengapa tidak $.preload(['img1.jpg', 'img2.jpg'])?
alex
12
Pastikan untuk memanggil ini di dalam $(window).load(function(){/*preload here*/});karena dengan cara itu semua gambar dalam dokumen dimuat terlebih dahulu, kemungkinan mereka diperlukan terlebih dahulu.
Jasper Kennis
12
@RegionalC - Mungkin sedikit lebih aman untuk mengatur loadacara sebelum mengatur untuk srcberjaga-jaga jika gambar selesai memuat sebelum acara memuat diatur? $('<img/>').load(function() { /* it's loaded! */ }).attr('src', this);
sparebytes
102

Inilah versi tweak dari respons pertama yang sebenarnya memuat gambar ke DOM dan menyembunyikannya secara default.

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img />').attr('src',this).appendTo('body').css('display','none');
    });
}
Dennis Rongo
sumber
38
hide()lebih singkat dari css('display', 'none').
alex
6
Apa keuntungan memasukkannya ke DOM?
alex
Saya juga ingin tahu keuntungan memasukkan mereka ke dalam DOM.
jedmao
11
Dari pengalaman saya, preloading gambar ke DOM membuat browser sadar akan keberadaannya dan untuk itu di-cache dengan benar. Jika tidak, gambar hanya ada di memori yang hanya berfungsi untuk aplikasi satu halaman.
Dennis Rongo
Dennis Rongo. Menambahkan gambar ke DOM tetap memuat ulang secara acak di Chrome. Terima kasih!
tmorell
52

Gunakan objek Gambar JavaScript .

Fungsi ini memungkinkan Anda untuk memicu panggilan balik setelah memuat semua gambar. Namun, perhatikan bahwa itu tidak akan pernah memicu panggilan balik jika setidaknya satu sumber daya tidak dimuat. Ini dapat dengan mudah diperbaiki dengan menerapkan onerrorpanggilan balik dan menambah loadednilai atau menangani kesalahan.

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
sumber
4
Lakukan hal yang benar, gunakan objek Gambar JavaScript. apakah Anda mengamati orang melakukan hal yang salah dalam jawaban ini?
alex
Kode brilian Apakah saya benar dalam berpikir bahwa ini akan memecat onloadacara bahkan jika gambar di-cache? (Karena img.onloaddideklarasikan terlebih dahulu). Inilah yang ditunjukkan oleh tes saya.
Startec
3
@ Alex berpotensi, ya. Jika tujuannya adalah untuk pra-muat (yang menunjukkan urutan kinerja) maka saya lebih suka melihat opsi JS mentah daripada opsi tergantung jQuery.
Charlie Schliesser
Saya menyukai solusi ini, tetapi saya baru tahu bahwa itu tidak berfungsi di Firefox saya. Apakah hanya saya atau orang lain yang memiliki masalah yang sama?
Gazillion
@Gazillion memberikan detail lebih lanjut. Bagaimana Anda mendefinisikan "tidak berfungsi"? Apa versi FF?
Gajus
35

JP, Setelah memeriksa solusi Anda, saya masih mengalami masalah di Firefox di mana itu tidak akan memuat gambar sebelum pindah bersama dengan memuat halaman. Saya menemukan ini dengan meletakkan beberapa sleep(5)di skrip sisi server saya. Saya menerapkan solusi berikut berdasarkan Anda yang tampaknya menyelesaikan ini.

Pada dasarnya saya menambahkan panggilan balik ke plugin prapuat jQuery Anda, sehingga dipanggil setelah semua gambar dimuat dengan benar.

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

Tidak menarik, dalam konteks saya, saya menggunakan ini sebagai berikut:

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

Semoga ini membantu seseorang yang datang ke halaman ini dari Google (seperti yang saya lakukan) mencari solusi untuk preloading gambar pada panggilan Ajax.

Dave
sumber
2
Bagi mereka yang tidak tertarik mengacaukan Array.prototype, Anda dapat melakukannya: checklist = this.lengthDan pada fungsi onload: checklist--Lalu:if (checklist == 0) callback();
MiniGod
3
Semuanya akan baik-baik saja tetapi menambahkan metode baru atau menghapus yang ada ke objek yang tidak Anda miliki adalah salah satu praktik terburuk dalam JavaScript.
Rihards
Bagus dan cepat, tetapi kode ini tidak akan pernah memecat callback jika salah satu gambar rusak atau tidak dapat dimuat.
SammyK
.attr({ src: this }).load(function() {...})seharusnya .load(function() {...}).attr({ src: this })kalau tidak Anda akan memiliki masalah caching.
Kevin B
25

Kode jQuery satu baris ini membuat (dan memuat) elemen DOM img tanpa memperlihatkannya:

$('<img src="img/1.jpg"/>');
rkcell
sumber
4
@huzzah - Anda mungkin lebih baik hanya menggunakan sprite. Lebih sedikit permintaan 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;
  });
};

Penggunaannya cukup sederhana:

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

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

yaart
sumber
Ini adalah jawaban yang sangat bagus, itu harus menjadi jawaban teratas yang dipilih imho.
sleepycal
1
Beberapa kata yang menjelaskan akan menyenangkan.
robsch
Jawaban yang bagus, tapi saya sarankan menggunakan picsum.photos daripada lorempixel.com
Aleksandar
19

Saya memiliki plugin kecil yang menangani ini.

Ini disebut waitForImages dan dapat menangani imgelemen atau elemen apa pun dengan referensi ke gambar di CSS, misalnya div { background: url(img.png) }.

Jika Anda hanya ingin memuat semua gambar, termasuk yang direferensikan dalam CSS, berikut adalah cara melakukannya :)

$('body').waitForImages({
    waitForAll: true,
    finished: function() {
       // All images have loaded.
    }  
});
alex
sumber
Apakah plugin ini menyebabkan gambar yang belum muncul pada halaman belum dimuat, atau hanya melampirkan acara ke gambar yang sudah akan dimuat?
Dave Cameron
@DaveCameron Tidak menghormati jika gambar terlihat atau tidak. Anda dapat dengan mudah memotongnya dan melakukan perubahan itu - cukup tambahkan :visibleke pemilih khusus.
alex
Plugin ini terlihat sangat menarik. Namun, dokumentasi jquery menyoroti bahwa loadacara tersebut, ketika diterapkan pada gambar: "tidak bekerja secara konsisten dan tidak dapat diandalkan lintas-browser". Bagaimana plugin berhasil menyiasatinya?
EleventyOne
@EleventyOne Periksa sumber terkait dengan pemilih kustom.
alex
@alex Bagaimana plugin ini memuat gambar yang diset di css on: hover suatu elemen? Itu tidak berhasil untuk saya
Philipp Hofmann
13

Anda dapat memuat gambar di html Anda di suatu tempat menggunakan css display:none; aturan , kemudian tunjukkan ketika Anda inginkan dengan js atau jquery

jangan gunakan fungsi js atau jquery untuk preload hanyalah aturan css Vs banyak baris js yang akan dieksekusi

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

Mem-preloading gambar dengan jquery / javascript tidak bagus karena gambar membutuhkan beberapa milidetik untuk memuat di halaman + Anda memiliki milidetik untuk skrip diurai dan dieksekusi, terutama jika itu adalah gambar besar, jadi menyembunyikannya dalam hml lebih baik juga untuk kinerja, menyebabkan gambar benar-benar dimuat tanpa terlihat sama sekali, sampai Anda menunjukkan itu!

ini aku
sumber
2
Info lebih lanjut tentang pendekatan ini dapat ditemukan di sini: perishablepress.com/...
gdelfino
3
Tetapi Anda perlu menyadari bahwa teknik ini memiliki kelemahan utama: halaman Anda tidak akan sepenuhnya dimuat sampai semua gambar dimuat. Bergantung pada jumlah gambar untuk dimuat dan ukurannya, ini bisa memakan waktu. Lebih buruk lagi, jika tag <img> tidak menentukan tinggi dan lebar, beberapa browser mungkin menunggu hingga gambar diambil sebelum membuat sisa halaman.
@Alex Anda tetap perlu memuat img, Anda bebas untuk memilih apakah memuatnya dengan html dan menghindari segala jenis gambar yang berkedip dan setengah dimuat, atau jika Anda ingin mendapatkan kecepatan lebih banyak untuk solusi yang tidak stabil
itsme
juga saya benar-benar berpikir membuat tag html dengan javascript tidak dapat dibaca sama sekali hanya 2 sen saya
itsme
1
Saya membutuhkan solusi yang sangat cepat untuk proyek yang sangat kompleks dan ini dia.
Germstorm
13

Plugin jquery imageLoader ini hanya 1,39kb

pemakaian:

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

ada juga opsi lain seperti apakah Anda ingin memuat gambar secara sinkron atau asikron dan acara lengkap untuk masing-masing gambar.

alzclarke
sumber
@ AmirAfridi Kenapa begitu?
Ian
1
@Ian karena dokumen sudah siap pada saat callback dipecat. $ (dokumen). Sudah digunakan untuk memastikan DOM Anda dimuat. Ketika datang ke panggilan balik, itu berarti bahwa semua gambar dimuat yang berarti bahwa DOM yoru dimuat sehingga tidak perlu untuk dokumen. Sudah di dalam panggilan balik.
Aamir Afridi
1
@ AmirAfridi Tidak ada jaminan bahwa dokumen siap di callback ... dari mana Anda dapat menyimpulkannya? Tidak ada di halaman plugin yang mengatakan bahwa allcompletecallback dijalankan setelah DOM siap. Ada kemungkinan yang cukup bagus bahwa gambar selesai dimuat setelah DOM siap, tetapi tidak ada alasan untuk menganggap. Saya tidak tahu mengapa Anda berpikir panggilan balik itu ajaib dan dieksekusi setelah DOM siap ... bisakah Anda menjelaskan dari mana Anda mendapatkannya? Hanya karena gambar dimuat bukan berarti DOM sudah siap
Ian
@ AmirAfridi Dan dokumentasi untuk plugin tersebut bahkan mengatakan: NB to use this as an image preloader simply put your $(document).ready(function(){}); into your 'allcomplete' event : > simples!... ia langsung merekomendasikan apa yang ditunjukkan oleh jawaban ini.
Ian
5
@ AmirAfridi Itu tidak masuk akal untuk situasi ini. Plugin ini adalah pre loader. Anda ingin menjalankannya sesegera mungkin. Dan ada banyak hal yang tidak bergantung pada DOM yang ingin Anda tembak sesegera mungkin, dan kemudian ketika DOM siap, lakukan sesuatu.
Ian
9

Cara cepat dan bebas plugin untuk memuat gambar di jQuery dan mendapatkan fungsi panggilan balik adalah membuat banyak imgtag sekaligus dan menghitung respons, mis.

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

Perhatikan bahwa jika Anda ingin mendukung IE7, Anda harus menggunakan versi yang sedikit kurang cantik ini (yang juga berfungsi di browser lain):

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

Terima kasih untuk ini! Saya ingin menambahkan sedikit riff pada jawaban JP - Saya tidak tahu apakah ini akan membantu siapa pun, tetapi dengan cara ini Anda tidak harus membuat array gambar, dan Anda dapat memuat semua gambar besar Anda jika Anda beri nama jempol Anda dengan benar. Ini berguna karena saya memiliki seseorang yang menulis semua halaman dalam html, dan itu memastikan satu langkah lebih sedikit untuk mereka lakukan - menghilangkan kebutuhan untuk membuat array gambar, dan langkah lain di mana hal-hal bisa kacau.

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

Pada dasarnya, untuk setiap gambar pada halaman itu meraih src dari setiap gambar, jika itu cocok dengan kriteria tertentu (adalah ibu jari, atau gambar halaman rumah) itu mengubah nama (string dasar diganti dalam gambar src), kemudian memuat gambar .

Dalam kasus saya, halaman itu penuh dengan gambar jempol semua bernama sesuatu seperti image_th.jpg, dan semua gambar besar yang sesuai bernama image_lg.jpg. Jempol ke besar hanya menggantikan _th.jpg dengan _lg.jpg dan kemudian memuat semua gambar besar.

Semoga ini bisa membantu seseorang.

dgig
sumber
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
sumber
7
Selamat Datang di Stack Overflow! Daripada hanya memposting blok kode, tolong jelaskan mengapa kode ini menyelesaikan masalah yang ditimbulkan. Tanpa penjelasan, ini bukan jawaban.
Martijn Pieters
3

Saya menggunakan kode berikut:

$("#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
sumber
Bind ke acara memuat pertama, lalu atur src.
Kevin B
1

Saya akan menggunakan file Manifest untuk memberi tahu browser (modern) untuk memuat semua gambar yang relevan dan menyimpannya. Gunakan Grunt dan grunt-manifes untuk melakukan ini secara otomatis dan jangan pernah khawatir lagi tentang preload script, cache invalidators, CDN dll.

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

Christian Landgren
sumber
0

Ini bekerja untuk saya bahkan di IE9:

$('<img src="' + imgURL + '"/>').on('load', function(){ doOnLoadStuff(); });
Zymotik
sumber
1
Ini pada akhirnya akan gagal karena caching, selalu ikat peristiwa pemuatan sebelum mengatur atribut src.
Kevin B
0

Saya ingin melakukan ini dengan hamparan khusus Google Maps API. Kode sampel mereka hanya menggunakan JS untuk memasukkan elemen IMG dan kotak placeholder gambar ditampilkan hingga gambar dimuat. Saya menemukan jawaban di sini yang berfungsi untuk saya: https://stackoverflow.com/a/10863680/2095698 .

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

Ini preload gambar seperti yang disarankan sebelumnya, dan kemudian menggunakan penangan untuk menambahkan objek img setelah URL img dimuat. Dokumentasi jQuery memperingatkan bahwa gambar yang di-cache tidak bekerja dengan baik dengan kode acara / penangan ini, tapi itu berfungsi untuk saya di FireFox dan Chrome, dan saya tidak perlu khawatir tentang IE.

bwinchester
sumber
Ini tidak akan bekerja dengan baik dengan gambar dalam tembolok seperti yang Anda temukan. solusinya adalah untuk mengikat acara memuat terlebih dahulu, lalu atur atribut src.
Kevin B
-1
function preload(imgs) {
    $(imgs).each(function(index, value) {
        $('<img />').attr('src', value).appendTo('body').css('display', 'none');
    });
}

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

hanya untuk menunjukkannya :)

Whisher
sumber
Lingkup thisdi dalam callback yang diteruskan $.eachditugaskan ke nilai yang sedang diulang.
Oybek
? $ (['img1.jpg', 'img2.jpg', 'img3.jpg']) masing-masing (fungsi (indeks, nilai) {console.log (value); // img1.jpg console.log (ini) ; // String {0 = "i", 1 = "m", 2 = "g", lebih ...} $ ('<img />'). Attr ('src', this) .appendTo (' body '). css (' display ',' none ');});
Whisher
Hm Saya kira Anda ada di sini. Misalnya $("div").each(function(i, el){ console.log(el == this);});menghasilkan semua trues; Iterasi over array tampaknya berperilaku berbeda.
Oybek
-2

5 baris dalam naskah kopi

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
sumber
2
Bisakah Anda memperluas bagaimana solusi bekerja untuk menyelesaikan pertanyaan di OP? Dan mungkin mengomentari kode Anda sehingga orang lain dapat lebih mudah memahaminya?
Ro Yo Mi
-4

Bagi mereka yang tahu sedikit actioncript, Anda dapat memeriksa flash player, dengan sedikit usaha, dan membuat preloader flash, yang juga dapat Anda ekspor ke html5 / Javascript / Jquery. Untuk menggunakan jika flash player tidak terdeteksi, lihat contoh bagaimana melakukan ini dengan peran youtube kembali ke html5 player :) Dan buat sendiri. Saya tidak memiliki detail, karena saya belum memulai, jika saya tidak lupa, saya akan mempostingnya nanti dan akan mencoba beberapa kode Jquery standerd untuk saya.

Peter Gruppelaar
sumber
Ini bukan solusi. Browser tidak mendukung Flash player secara default. Ini dapat dengan mudah dicapai dengan JavaScript yang merupakan bahasa browser asli.
Usman Ahmed
Saya ingat pembenci Flash dari 2012 ... itu tidak normal ... ke mana pun saya pergi saya diserang ketika saya bahkan menggunakan kata Flash.
Peter Gruppelaar