jQuery โทรกลับในการโหลดภาพ (แม้ในขณะที่ภาพแคช)


291

ฉันต้องการทำ:

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

แต่เหตุการณ์โหลดไม่เริ่มทำงานเมื่อโหลดภาพจากแคช jQuery docsแนะนำให้ใช้ปลั๊กอินเพื่อแก้ไขปัญหานี้ แต่มันไม่ทำงาน


12
ตั้งแต่คำถามของคุณมีการเปลี่ยนแปลง ปลั๊กอินเสียก็ถูกย้ายไปสรุปสาระสำคัญและภายหลังการซื้อคืนที่มีการทำงานเล็ก ๆ ปลั๊กอิน jQuery.imagesLoaded พวกเขาจะแก้ไขทุกนิสัยใจคอเบราว์เซอร์เล็ก ๆ น้อย ๆ
แร่

ดังกล่าวข้างต้นห้องสมุด JQuery ทำงานได้ดีสำหรับฉัน ขอบคุณ!
plang

ขอบคุณสำหรับปลั๊กอินมันใช้งานได้ดี
onimojo

คำตอบ:


572

หากsrcตั้งค่าไว้แล้วเหตุการณ์จะเริ่มทำงานในกรณีที่แคชก่อนที่คุณจะได้รับตัวจัดการเหตุการณ์ที่ถูกผูกไว้ ในการแก้ไขปัญหานี้คุณสามารถวนซ้ำการตรวจสอบและกระตุ้นให้เกิดเหตุการณ์ตาม.completeเช่นนี้:

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

บันทึกการเปลี่ยนแปลงจาก.bind()เป็น.one()เพื่อให้ตัวจัดการเหตุการณ์ไม่ทำงานสองครั้ง


8
วิธีการแก้ปัญหาของคุณทำงานได้สมบูรณ์แบบสำหรับฉัน แต่ฉันต้องการที่จะเข้าใจบางสิ่งบางอย่างเมื่อรหัสนี้ "ถ้า (this.complete)" จะทำงานหลังจากที่เนื้อหาของภาพโหลดหรือก่อน? เพราะอย่างที่ฉันสามารถเข้าใจได้จากนี้. แต่ละครั้งที่คุณวนลูปทั้งหมด $ ("img") และอาจเป็นเนื้อหารูปภาพว่างเปล่าและการโหลดจะไม่เกิดขึ้น อืมฉันคิดว่าฉันมีบางอย่างขาดหายไปมันจะดีถ้าคุณสามารถอธิบายได้ว่ามันเกิดขึ้นเพื่อทำความเข้าใจให้ดีขึ้น ขอบคุณ
Amr Elgarhy

33
ตั้งแต่สิ่งที่คำตอบของคุณมีการเปลี่ยนแปลง ขณะนี้มีการทำงานเล็ก ๆ ปลั๊กอิน jQuery.imagesLoaded พวกเขาจะแก้ไขทุกนิสัยใจคอเบราว์เซอร์เล็ก ๆ น้อย ๆ
แร่

3
ฉันจะเพิ่มsetTimeout(function(){//do stuff},0)ภายใน 'โหลด' ฟังก์ชั่น ... 0ให้ระบบเบราว์เซอร์ (DOM) เห็บพิเศษหนึ่งเพื่อให้แน่ใจว่าทุกอย่างมีการปรับปรุงอย่างถูกต้อง
dsdsdsdsd

14
@Lode - มันเป็นปลั๊กอินขนาดใหญ่ไม่เล็กเลยแม้แต่นิดเดียว !!
vsync

5
เนื่องจากเมธอด JQuery 3 .load()ไม่ทริกเกอร์เหตุการณ์และมีอาร์กิวเมนต์ที่จำเป็น 1 ข้อให้ใช้.trigger("load")แทน
ForceUser

48

ฉันขอแนะนำให้คุณโหลดมันใหม่ไปเป็นวัตถุอิมเมจที่ไม่ใช่ DOM ได้ไหม? หากแคชแล้วจะไม่ใช้เวลาเลยและ onload จะยังคงทำงานต่อไป หากไม่มีการแคชแคชจะทำการโหลด onload เมื่อโหลดอิมเมจซึ่งควรเป็นเวลาเดียวกันกับที่เวอร์ชัน DOM ของอิมเมจเสร็จสิ้นการโหลด

javascript:

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

อัปเดต (เพื่อจัดการภาพหลายภาพและมีไฟล์แนบ onload ที่สั่งซื้ออย่างถูกต้อง):

$(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
คุณควรพยายามที่จะแนบloadจัดการก่อนที่มันเพิ่มยังนี้จะไม่ทำงาน แต่สำหรับภาพหนึ่งตรวจการณ์การทำงานสำหรับหลาย ๆ :)
นิค Craver

ขอขอบคุณฉันได้เพิ่มเวอร์ชันที่อัปเดตแล้วซึ่งฉันหวังว่าจะสามารถแก้ไขปัญหาทั้งสองนี้ได้
กัส

#imgเป็น ID ไม่ใช่ตัวเลือกองค์ประกอบ :) ใช้this.srcงานได้โดยไม่จำเป็นต้องใช้ jQuery โดยที่ไม่จำเป็น :) แต่การสร้างภาพอื่นดูเหมือนว่า overkill ในกรณี IMO
Nick Craver

ควรเป็น $ ('img') แต่การแก้ปัญหาคือ gr8 ใน 2k15 ด้วย
Dimag Kharab

นอกจากนี้สำหรับกรณีรูปภาพหลายกรณีหากคุณต้องการใช้งานองค์ประกอบ DOM สำหรับแต่ละภาพimageLoadedให้ใช้tmp.onload = imageLoaded.bind(this)
blisstdev

38

โซลูชันที่เรียบง่ายของฉันไม่จำเป็นต้องใช้ปลั๊กอินภายนอกและสำหรับกรณีทั่วไปควรจะเพียงพอ:

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

ใช้มันแบบนี้:

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

ตัวอย่างเช่นในการโหลดภาพของคุณให้จางลงคุณสามารถทำได้:

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

หรือเป็นทางเลือกถ้าคุณชอบแนวทางคล้ายกับ 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);

และใช้วิธีนี้:

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

ตัวอย่างเช่น:

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

.. แล้วจะทำอย่างไรถ้าภาพของฉันมีขนาดเท่ากับ css
Simon_Weaver

ชุดwidth, max-heightและลาheight:autoมักจะเป็นสิ่งจำเป็นในการตั้งค่าทั้งความกว้างและความสูงเพียงถ้าคุณจำเป็นต้องยืดภาพ; สำหรับโซลูชันที่มีประสิทธิภาพยิ่งขึ้นฉันจะใช้ปลั๊กอินเช่นImagesLoaded
guari

1
ใช่มันเป็นความผิดพลาด jsdoc ก็โอเคฉันแก้ไขตัวอย่างบรรทัด
guari

1
โซลูชันนี้พร้อม $ .fn.imgLoad ทำงานกับเบราว์เซอร์ การแก้ไขจะดียิ่งขึ้น: && / * สำหรับ IE 10 - * / this.naturalHeight> 0 บรรทัดนี้จะไม่ใช้รูปแบบ CSS เพื่อพิจารณาเนื่องจาก img สามารถบล็อกได้ แต่มีความสูง ทำงานใน IE10
Patryk Padus

1
นี่เป็นเงื่อนไขการแข่งขัน (เล็ก) รูปภาพสามารถโหลดในเธรดอื่นไปยังสคริปต์และสามารถโหลดระหว่างการตรวจสอบความสมบูรณ์และการแนบเหตุการณ์ onload ซึ่งในกรณีนี้จะไม่มีอะไรเกิดขึ้น โดยปกติ JS จะซิงโครนัสกับการเรนเดอร์และคุณไม่ต้องกังวลเกี่ยวกับสภาพการแข่งขัน แต่นี่เป็นข้อยกเว้น html.spec.whatwg.org/multipage/…
Mog0

23

คุณต้องทำกับ jQuery จริงๆเหรอ? คุณสามารถแนบonloadกิจกรรมโดยตรงกับภาพของคุณเช่นกัน

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

มันจะเริ่มทำงานทุกครั้งที่โหลดภาพจากแคชหรือไม่


5
ทำความสะอาดโดยไม่ใช้ javascript แบบอินไลน์
hazelnut

1
สวัสดี Bjorn onloadตัวจัดการจะเริ่มทำงานเมื่อภาพถูกโหลดครั้งที่สองจากแคชหรือไม่
SexyBeast

1
@Cupidvogel ไม่ได้
โฆษณา

3
เพื่อนคุณช่วยชีวิตฉันฉันพยายามอย่างน้อยหนึ่งวิธีแก้ปัญหาอื่น ๆ และคุณเป็นคนเดียวที่ได้ผลจริง ฉันคิดอย่างจริงจังเกี่ยวกับการสร้างบัญชีอีก 10 บัญชีเพื่อโหวตคำตอบของคุณอีก 10 ครั้ง ขอบคุณอย่างจริงจัง!
คาร์โล

1
ฉันไม่เคยเข้าใจความเกลียดชังของผู้คนที่มีต่ออินไลน์ JS การโหลดรูปภาพเกิดขึ้นแยกจากกันและไม่อยู่ในลำดับที่เหลือจากกระบวนการโหลดหน้าเว็บ ดังนั้นนี่เป็นทางออกที่ถูกต้องเพียงข้อเดียวในการรับความคิดเห็นทันทีเกี่ยวกับการโหลดภาพที่เสร็จสมบูรณ์ อย่างไรก็ตามหากมีคนต้องการรอให้ jQuery โหลดและเกิดขึ้นในภายหลังพวกเขาจะไม่ต้องใช้วิธีแก้ปัญหาง่ายๆที่นี่และใช้วิธีแก้ปัญหาอื่น ๆ (Piotr อาจเป็นตัวเลือกที่ดีที่สุดเนื่องจากไม่ได้ขึ้นอยู่กับการหลอก แฮ็ก แต่ความสูงของ guari () การตรวจสอบอาจมีความสำคัญเช่นกัน) คิวการประมวลผลอาจมีประโยชน์เช่นกัน
CubicleSoft

16

นอกจากนี้คุณยังสามารถใช้รหัสนี้พร้อมการสนับสนุนสำหรับข้อผิดพลาดในการโหลด:

$("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
อันนี้ใช้ได้ดีที่สุดสำหรับฉัน ฉันคิดว่ากุญแจสำคัญคือการตั้งค่าloadตัวจัดการก่อนแล้วจึงเรียกมันภายหลังในeachฟังก์ชั่น
GreenRaccoon23

การตั้งค่าภาพโดยใช้รหัสด้านล่าง '' var img = ภาพใหม่ (); img.src = sosImgURL; $ (img) .on ("load", function () {''
imdadhusen

13

ฉันเพิ่งพบปัญหานี้ด้วยตัวเองค้นหาทุกที่เพื่อหาทางออกที่ไม่เกี่ยวข้องกับการฆ่าแคชหรือดาวน์โหลดปลั๊กอิน

ฉันไม่เห็นกระทู้นี้ทันทีดังนั้นฉันจึงพบสิ่งอื่นแทนซึ่งเป็นการแก้ไขที่น่าสนใจและ (ฉันคิดว่า) ควรค่าแก่การโพสต์ที่นี่:

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

ที่จริงฉันได้ความคิดนี้จากความคิดเห็นที่นี่: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

ฉันไม่รู้ว่าทำไมมันใช้งานได้ แต่ฉันได้ทดสอบสิ่งนี้บน IE7 และที่ที่มันพังก่อนที่มันจะทำงาน

หวังว่าจะช่วย

แก้ไข

คำตอบที่ยอมรับได้จริงอธิบายว่าทำไม:

หาก src ถูกตั้งค่าไว้เหตุการณ์จะเริ่มทำงานในแคชก่อนที่คุณจะได้รับตัวจัดการเหตุการณ์


4
ฉันทดสอบแล้วว่ามันมีอยู่ในเบราว์เซอร์จำนวนมากและไม่พบว่ามันล้มเหลว ฉันใช้$image.load(function(){ something(); }).attr('src', $image.attr('src'));เพื่อตั้งค่าต้นฉบับดั้งเดิม
มอริซ

ฉันพบว่าวิธีการนี้ใช้ไม่ได้กับ iOS อย่างน้อยสำหรับ Safari / 601.1 และ Safari / 602.1
cronfy

น่าจะรู้ว่าทำไมเบราว์เซอร์มันคืออะไร
Sammaye

5

โดยใช้ jQuery เพื่อสร้างรูปภาพใหม่ด้วย src ของรูปภาพและกำหนดวิธีการโหลดโดยตรงกับวิธีนั้นโหลดวิธีจะถูกเรียกสำเร็จเมื่อ jQuery เสร็จสิ้นการสร้างภาพใหม่ สิ่งนี้ใช้ได้กับฉันใน IE 8, 9 และ 10

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

สำหรับผู้ที่ใช้ Ruby on Rails ด้วยการร้องขอจากระยะไกลโดยใช้เทมเพลต __rjs.erb นี่เป็นทางออกเดียวที่ฉันได้พบ เนื่องจากการใช้งาน partials ใน js.erb จึงทำให้มีผลผูกพัน ($ ("# img" .on ("load") ... ) และสำหรับภาพไม่สามารถมอบหมายวิธี "on": $ ("body") เปิด ("load", "# img", function () ...
Albert Català

5

วิธีการแก้ปัญหาที่ฉันพบhttps://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (รหัสนี้นำมาโดยตรงจากความคิดเห็น)

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

นี่คือสิ่งที่ฉันกำลังมองหา รูปเดียวมาหาฉันจากเซิร์ฟเวอร์ ฉันต้องการโหลดล่วงหน้าและรับใช้แล้ว ไม่เลือกภาพทั้งหมดเหมือนคำตอบมากมาย สิ่งที่ดี.
Kai Qing

4

การดัดแปลงตัวอย่างของ GUS:

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

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

ตั้งค่าซอร์สก่อนและหลัง onload


เช่นเดียวกับคำตอบของ @ Gus สิ่งนี้จะไม่ทำงานสำหรับหลายภาพ ... และไม่จำเป็นต้องตั้งค่าsrcก่อนที่จะติดตั้งเครื่องonloadจัดการหลังจากนั้นจะพอเพียง
Nick Craver

3

เพียงเพิ่มอาร์กิวเมนต์ src อีกครั้งในบรรทัดแยกต่างหากหลังจากที่มีการกำหนด img oject สิ่งนี้จะหลอก IE ในการกระตุ้นเหตุการณ์เด็กหนุ่ม มันน่าเกลียด แต่ก็เป็นวิธีแก้ปัญหาที่ง่ายที่สุดที่ฉันเคยพบมา

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

1

ฉันสามารถให้คำแนะนำเล็กน้อยแก่คุณได้หากคุณต้องการทำสิ่งนี้:

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

หากคุณทำเช่นนั้นเมื่อเบราว์เซอร์เก็บรูปภาพจะไม่มีปัญหา img แสดงขึ้นเสมอ แต่โหลด img ภายใต้ภาพจริง


1

ฉันมีปัญหากับ IE ที่ e.target.width นี้จะไม่ได้กำหนด เหตุการณ์โหลดจะเริ่มขึ้น แต่ฉันไม่สามารถรับขนาดของภาพใน IE (chrome + FF ทำงาน)

เปิดออกคุณต้องมองหาe.currentTarget.naturalWidth & e.currentTarget.naturalHeight

อีกครั้ง IE ทำสิ่งต่าง ๆ เป็นของตัวเอง (ซับซ้อนกว่า)


0

คุณสามารถแก้ปัญหาของคุณโดยใช้ปลั๊กอินJAILที่ช่วยให้คุณสามารถโหลดภาพที่ขี้เกียจ (ปรับปรุงประสิทธิภาพของหน้า) และผ่านการเรียกกลับเป็นพารามิเตอร์

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

HTML ควรมีลักษณะดังนี้

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

0

หากคุณต้องการโซลูชัน CSS ที่บริสุทธิ์เคล็ดลับนี้ใช้ได้ดีมาก - ใช้วัตถุแปลง วิธีนี้ใช้ได้กับรูปภาพเมื่อแคชหรือไม่:

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

ตัวอย่าง Codepen

ตัวอย่าง Codepen LESS


คุณช่วยยกตัวอย่างวิธีการทำงานของการโหลดภาพได้ไหม
Hastig Zusammenstellen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.