jQuery callback saat memuat gambar (bahkan saat gambar di-cache)

291

Aku ingin melakukan:

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

Tetapi acara memuat tidak menyala ketika gambar diambil dari cache. Dokumen jQuery menyarankan plugin untuk memperbaikinya, tetapi tidak berfungsi

Tom Lehman
sumber
12
Karena pertanyaan Anda banyak hal telah berubah. Plugin yang rusak dipindahkan ke inti dan kemudian ke repo dengan jQuery.imagesLoaded plugin yang berfungsi kecil . Mereka memperbaiki semua kebiasaan browser kecil .
Lode
Pustaka JQuery yang disebutkan di atas bekerja dengan baik untuk saya. Terima kasih!
plang
Terima kasih atas pluginnya, itu berfungsi dengan baik.
onimojo

Jawaban:

572

Jika srcsudah diatur, maka acara menembak dalam kasus di-cache, bahkan sebelum Anda terikat event handler. Untuk memperbaikinya, Anda bisa mengulang memeriksa dan memicu acara didasarkan .complete, seperti ini:

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

Perhatikan perubahan dari .bind()ke .one()sehingga event handler tidak berjalan dua kali.

Nick Craver
sumber
8
Solusi Anda berfungsi sempurna untuk saya, tetapi saya ingin memahami sesuatu, ketika kode ini "if (this.complete)" akan berjalan, setelah konten gambar dimuat atau sebelumnya? karena seperti yang saya bisa pahami dari ini. masing-masing bahwa Anda mengulang semua $ ("img") dan mungkin isi gambar kosong dan beban tidak akan terjadi. hmmmm, saya pikir saya memiliki sesuatu yang hilang, akan lebih baik jika Anda bisa menggambarkan yang terjadi untuk memahaminya dengan lebih baik. Terima kasih.
Amr Elgarhy
33
Karena jawaban Anda telah berubah. Sekarang ada plugin jQuery.imagesLoaded yang berfungsi kecil . Mereka memperbaiki semua kebiasaan browser kecil .
Lode
3
Saya akan menambahkan setTimeout(function(){//do stuff},0)dalam fungsi 'memuat' ... 0 memberi satu centang tambahan sistem browser (DOM) untuk memastikan bahwa semuanya diperbarui dengan benar.
dsdsdsdsd
14
@Lode - ini adalah plugin BESAR, tidak kecil sama sekali dengan skala apa pun !!
vsync
5
sejak JQuery 3 metode .load()tidak memicu acara dan memiliki 1 argumen yang diperlukan, gunakan .trigger("load")bukan
ForceUser
48

Dapatkah saya menyarankan Anda memuatnya kembali ke objek gambar non-DOM? Jika di-cache, ini tidak akan memakan waktu sama sekali, dan muatannya masih akan menyala. Jika tidak di-cache, itu akan mem-onload ketika gambar dimuat, yang harus menjadi waktu yang sama dengan versi DOM dari gambar selesai memuat.

Javascript:

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

Diperbarui (untuk menangani beberapa gambar dan dengan lampiran yang dipesan dengan benar):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;
Gus
sumber
1
Anda harus mencoba untuk melampirkan loadpawang sebelum ditambahkan, juga ini tidak akan berfungsi tetapi untuk satu gambar, kode OP bekerja untuk banyak :)
Nick Craver
Terima kasih, saya telah menambahkan versi terbaru yang saya harap membahas dua masalah ini.
Gus
#imgadalah ID bukan elemen pemilih :) Juga this.srcberfungsi, tidak perlu menggunakan jQuery di mana itu tidak diperlukan :) Tapi membuat gambar lain sepertinya berlebihan dalam IMO.
Nick Craver
seharusnya $ ('img'). tetapi solusinya adalah gr8 di 2k15 juga
Dimag Kharab
Juga, untuk imageLoadedtmp.onload = imageLoaded.bind(this)
kasing
38

Solusi sederhana saya, tidak memerlukan plugin eksternal dan untuk kasus umum seharusnya sudah cukup:

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

gunakan seperti ini:

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

misalnya, untuk memudar pada gambar Anda saat memuat yang dapat Anda lakukan:

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

Atau sebagai alternatif, jika Anda lebih suka pendekatan seperti plugin 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);

dan gunakan dengan cara ini:

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

sebagai contoh:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});
guari
sumber
urm .. dan bagaimana jika gambar saya memiliki ukuran yang diatur dengan css?
Simon_Weaver
Atur width, max-heightdan tinggalkan height:auto, seringkali perlu mengatur lebar dan tinggi hanya jika Anda perlu meregangkan gambar; untuk solusi yang lebih kuat saya akan menggunakan plugin seperti ImagesLoaded
guari
1
ya itu salah ketik, jsdoc ok, saya koreksi contoh baris
guari
1
Solusi ini dengan $ .fn.imgLoad berfungsi di seluruh browser. Memperbaikinya akan lebih baik: && / * untuk IE 10 - * / this.naturalHeight> 0 Baris ini tidak akan mempertimbangkan gaya css karena img dapat diblokir tetapi memiliki ketinggian. Bekerja di IE10
Patryk Padus
1
Ini memang memiliki kondisi balapan (kecil). Gambar dapat memuat di utas yang berbeda ke skrip dan juga dapat memuat antara pemeriksaan selesai dan melampirkan acara onload, dalam hal ini tidak ada yang akan terjadi. Biasanya JS sinkron dengan rendering dan jadi Anda tidak perlu khawatir tentang kondisi balapan tapi ini pengecualian. html.spec.whatwg.org/multipage/…
Mog0
23

Apakah Anda benar-benar harus melakukannya dengan jQuery? Anda dapat melampirkan onloadacara langsung ke gambar Anda juga;

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

Itu akan menyala setiap kali gambar telah dimuat, dari cache atau tidak.

Björn
sumber
5
Ini lebih bersih tanpa javascript inline
hazelnut
1
Hai, Bjorn, akankah onloadhandler menyala ketika gambar diambil untuk kedua kalinya dari cache?
SexyBeast
1
@Cupidvogel tidak, itu tidak akan.
Iklan
3
Bung, Anda menyelamatkan hidup saya, saya sudah mencoba setidaknya selusin solusi lain dan Anda adalah satu-satunya yang benar-benar berhasil. Saya serius berpikir untuk membuat 10 lebih banyak akun untuk memilih jawaban Anda hingga 10 kali lebih banyak. Terima kasih banyak!
Carlo
1
Saya tidak pernah mengerti penolakan orang terhadap inline JS. Pemuatan gambar terjadi secara terpisah dan di luar urutan dari sisa proses pemuatan halaman. Oleh karena itu, ini adalah satu-satunya solusi yang valid untuk mendapatkan umpan balik segera tentang penyelesaian pemuatan gambar. Namun, jika seseorang perlu menunggu jQuery untuk memuat dan itu terjadi kemudian, maka mereka harus tidak menggunakan solusi sederhana di sini dan menggunakan salah satu solusi lain (Piotr mungkin merupakan pilihan terbaik karena tidak tergantung pada pseudo- retasan tetapi tinggi guari () mungkin juga penting). Antrian pemrosesan juga bisa bermanfaat.
CubicleSoft
16

Anda juga dapat menggunakan kode ini dengan dukungan untuk memuat kesalahan:

$("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();
    }
});
Piotr Stępniewski
sumber
1
Yang ini bekerja paling baik untuk saya. Saya pikir kuncinya adalah mengatur loadhandler terlebih dahulu dan kemudian memanggilnya nanti dalam eachfungsinya.
GreenRaccoon23
pengaturan gambar menggunakan kode di bawah ini '' var img = Gambar baru (); img.src = sosImgURL; $ (img) .on ("load", function () {''
imdadhusen
13

Saya sendiri hanya mengalami masalah ini, mencari di mana-mana solusi yang tidak melibatkan mematikan cache atau mengunduh plugin.

Saya tidak melihat utas ini segera jadi saya menemukan sesuatu yang bukan perbaikan yang menarik dan (saya pikir) layak untuk diposkan di sini:

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

Saya sebenarnya mendapat ide ini dari komentar di sini: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

Saya tidak tahu mengapa ini bekerja tetapi saya telah menguji ini pada IE7 dan di mana ia rusak sebelum sekarang bekerja.

Semoga ini bisa membantu,

Edit

Jawaban yang diterima sebenarnya menjelaskan mengapa:

Jika src sudah disetel maka event menembakkan cache yang sudah di-cache sebelum Anda mengikat event handler.

Sammaye
sumber
4
Saya telah menguji ini di banyak browser dan belum menemukannya gagal di mana pun. Saya biasa $image.load(function(){ something(); }).attr('src', $image.attr('src'));mereset sumber aslinya.
Maurice
Saya menemukan bahwa pendekatan ini tidak berfungsi di iOS, setidaknya untuk Safari / 601.1 dan Safari / 602.1
cronfy
Akan luar biasa untuk mencari tahu mengapa, di browser apa itu?
Sammaye
5

Dengan menggunakan jQuery untuk menghasilkan gambar baru dengan src gambar, dan menetapkan metode pemuatan langsung untuk itu, metode pemuatan berhasil dipanggil ketika jQuery selesai menghasilkan gambar baru. Ini berfungsi untuk saya di IE 8, 9 dan 10

$('<img />', {
    "src": $("#img").attr("src")
}).load(function(){
    // Do something
});
nick
sumber
Bagi mereka yang menggunakan Ruby on Rails, dengan permintaan jarak jauh, menggunakan templat __rjs.erb, ini adalah satu-satunya solusi yang saya temukan. Karena menggunakan parsial di js.erb, ia kehilangan ikatan ($ ("# img" .on ("load") ... dan untuk gambar TIDAK mungkin mendelegasikan metode "on": $ ("body"). pada ("memuat", "# img", function () ...
Albert Català
5

Solusi yang saya temukan https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (Kode ini diambil langsung dari komentar)

var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;
AllisonC
sumber
Ini persis apa yang saya cari. Satu gambar datang kepada saya dari server. Saya ingin memuatnya dan kemudian melayani. Tidak memilih semua gambar seperti banyak jawaban. Bagus
Kai Qing
4

Modifikasi pada contoh GUS:

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

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

Atur sumber sebelum dan sesudah onload.

Chuck Conway
sumber
Seperti jawaban @ Gus, ini tidak akan berfungsi untuk banyak gambar ... dan tidak perlu mengatur srcsebelum memasang onloadhandler, setelah itu sudah cukup.
Nick Craver
3

Cukup tambahkan kembali argumen src pada baris yang terpisah setelah img oject didefinisikan. Ini akan menipu IE untuk memicu event-lad. Ini jelek, tapi ini solusi paling sederhana yang saya temukan sejauh ini.

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

Saya bisa memberi Anda sedikit tip jika Anda ingin melakukan ini:

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

Jika Anda melakukan itu ketika peramban menyimpan gambar, tidak masalah selalu ditampilkan tetapi memuat gambar di bawah gambar asli.

Josephy Besim
sumber
1

Saya punya masalah dengan IE ini dimana e.target.width akan tidak terdefinisi. Acara memuat akan menyala tetapi saya tidak bisa mendapatkan dimensi gambar di IE (chrome + FF berfungsi).

Ternyata Anda perlu mencari e.currentTarget.naturalWidth & e.currentTarget.naturalHeight .

Sekali lagi, IE melakukan hal-hal dengan caranya sendiri (lebih rumit).

Ali
sumber
0

Anda dapat menyelesaikan masalah Anda menggunakan plugin JAIL yang juga memungkinkan Anda untuk malas memuat gambar (meningkatkan kinerja halaman) dan meneruskan panggilan balik sebagai parameter

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

HTML akan terlihat seperti

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

Jika Anda menginginkan solusi CSS murni, trik ini berfungsi sangat baik - gunakan objek transformasi. Ini juga berfungsi dengan gambar ketika di-cache atau tidak:

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

Contoh codepen

Contoh codepen KURANG

neoRiley
sumber
Bisakah Anda memberikan contoh cara kerjanya dengan memuat gambar?
Hastig Zusammenstellen