วิธีการอย่างเป็นทางการในการขอให้ jQuery รอให้โหลดรูปภาพทั้งหมดก่อนดำเนินการบางอย่าง


641

ใน jQuery เมื่อคุณทำสิ่งนี้:

$(function() {
   alert("DOM is loaded, but images not necessarily all loaded");
});

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

สมมติว่าฉันต้องการภาพเคลื่อนไหวและฉันไม่ต้องการให้มันทำงานจนกว่าภาพทั้งหมดจะถูกโหลด มีวิธีอย่างเป็นทางการใน jQuery ในการทำเช่นนี้หรือไม่?

วิธีที่ดีที่สุดที่ฉันต้องใช้<body onload="finished()">คือ แต่ฉันไม่ต้องการทำอย่างนั้นจริง ๆ เว้นแต่ฉันจะต้องทำ

หมายเหตุ: มีเป็นข้อผิดพลาดใน jQuery 1.3.1ใน Internet Explorer $function() { }ซึ่งอันที่จริงไม่ต้องรอให้ภาพทุกภาพที่จะโหลดก่อนที่จะดำเนินภายในรหัส ดังนั้นหากคุณกำลังใช้แพลตฟอร์มนั้นคุณจะได้รับพฤติกรรมที่ฉันกำลังมองหาแทนที่จะเป็นพฤติกรรมที่ถูกต้องที่อธิบายไว้ข้างต้น


3
ไม่$("img").load()ทำงานใช่ไหม
ลูคัส

1
ฉันคิดว่ามันอาจคุ้มค่าที่จะกล่าวถึงว่าหากคุณตั้งค่าคุณลักษณะส่วนข้อมูลคุณสามารถรันโค้ดบางส่วนในฟังก์ชั่นพร้อมใช้ที่ปลอดภัยขึ้นอยู่กับส่วนข้อมูลเหล่านั้น ด้วย php คุณสามารถคว้ามันด้วยphp.net/manual/en/function.getimagesize.phpในการอัพโหลดเพื่อเก็บไว้ในฐานข้อมูลหรือก่อนที่จะส่งออกไปยังเบราว์เซอร์
Alqin

หากคุณต้องการทำงานที่น่าเหลือเชื่อลองไปที่ห้องสมุดจาวาสคริปต์ imagesloaded ที่ได้รับความนิยมและยอดเยี่ยมที่กล่าวถึงในคำตอบนี้ด้านล่างstackoverflow.com/a/26458347/759452
Adrien Be

"ฉันมาที่นี่เพื่อหาอะไรนอกจากวิธีเป็นทางการ"
Léon Pelletier

คำตอบ:


1035

ด้วย jQuery คุณใช้$(document).ready()ในการดำเนินการบางอย่างเมื่อโหลดDOMและ$(window).on("load", handler)ดำเนินการบางอย่างเมื่อโหลดสิ่งอื่นทั้งหมดด้วยเช่นรูปภาพ

ความแตกต่างสามารถเห็นได้ในไฟล์ HTML สมบูรณ์ต่อไปนี้หากคุณมีjollyrogerไฟล์ JPEG (หรือไฟล์อื่นที่เหมาะสม):

<html>
    <head>
        <script src="jquery-1.7.1.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                alert ("done");
            });
        </script>
    </head><body>
        Hello
        <img src="jollyroger00.jpg">
        <img src="jollyroger01.jpg">
        // : 100 copies of this
        <img src="jollyroger99.jpg">
    </body>
</html>

เมื่อถึงตอนนั้นกล่องการแจ้งเตือนจะปรากฏขึ้นก่อนที่จะโหลดรูปภาพเนื่องจาก DOM พร้อมใช้งาน ณ จุดนั้น หากคุณเปลี่ยนแล้ว:

$(document).ready(function() {

เป็น:

$(window).on("load", function() {

แล้วกล่องเตือนไม่ปรากฏจนกระทั่งหลังจากที่ภาพจะถูกโหลด

ดังนั้นเพื่อรอจนกว่าทั้งหน้าจะพร้อมคุณสามารถใช้สิ่งที่ชอบ:

$(window).on("load", function() {
    // weave your magic here.
});

32
smacks หน้าผาก +1 ลืมไปหมดเลย $ (หน้าต่าง) .load () จะไม่ทำงานจนกว่าภาพจะเสร็จ
เปาโล Bergantino

10
ฉันทำแบบเดียวกัน แม้แต่อ่านคำตอบที่ไม่รู้ว่าเป็นฉันและยังไม่เข้าใจ
Rimian

24
แค่ทราบ - ดูเหมือนว่าจะไม่ทำงานภายใต้ Chromium (และฉันถือว่า Chrome) เหตุการณ์ $ (หน้าต่าง) .ready ดูเหมือนว่าจะเหมือนกับ $ (เอกสาร) .ready - ก่อนที่ภาพจะเสร็จสมบูรณ์
Nathan Crause

24
แต่มันเป็น $ (หน้าต่าง) .load (function ())
TJ-

3
@KyorCode คุณแน่ใจหรือไม่ว่าเป็นเพราะรูปภาพใน IE ถูกแคชไว้? หากสิ่งนั้นเกิดขึ้นพวกเขาจะไม่ดำเนินการเหตุการณ์ "โหลด" เลย บทความนี้ช่วยแก้ไขปัญหานี้ได้
Jamie Barker

157

ฉันเขียนปลั๊กอินที่สามารถเรียกกลับเมื่อมีการโหลดภาพในองค์ประกอบหรือยิงหนึ่งครั้งต่อภาพที่โหลด

มันคล้ายกับ$(window).load(function() { .. })ยกเว้นช่วยให้คุณกำหนดตัวเลือกใด ๆ ที่จะตรวจสอบ หากคุณต้องการทราบว่าเมื่อใดที่#contentโหลดรูปภาพทั้งหมดใน(ตัวอย่าง) นี่เป็นปลั๊กอินสำหรับคุณ

นอกจากนี้ยังสนับสนุนการโหลดภาพอ้างอิงใน CSS เช่นbackground-image, list-style-imageฯลฯ

waitForImages jQuery ปลั๊กอิน

  • พื้นที่เก็บข้อมูล GitHub
  • อ่านแล้ว
  • แหล่งที่มาของการผลิต
  • แหล่งที่มาของการพัฒนา

ตัวอย่างการใช้งาน

$('selector').waitForImages(function() {
    alert('All images are loaded.');
});

ตัวอย่างเช่นใน jsFiddle

เอกสารเพิ่มเติมมีอยู่ในหน้า GitHub


1
ขอบคุณ!! $ .load () ไม่ได้ผลสำหรับฉัน แต่นี่เป็นกลอุบายที่สมบูรณ์แบบ
Fraxtil

ฉันใช้ Chrome เวอร์ชัน 22.0.1229.94 และปลั๊กอินนี้และฉันพยายามอ่านออฟเซ็ตจากรูปภาพที่โหลดภายใน waitFormImages: ('img selector').each(function(index) { var offset = $(this).offset(); ...});อย่างไรก็ตาม offset.top ยังคงเป็นศูนย์ ทำไม?
basZero

1
@basZero ยากที่จะบอกโดยไม่มีบริบทเพิ่มเติม โปรดแจ้งปัญหาในหน้าปัญหา
alex

มันไม่ทำงานสำหรับฉันเมื่อมีการถ่ายภาพ any1 มีวิธีแก้ปัญหาสำหรับสิ่งนี้หรือไม่?
Mandeep Jain

2
โดยพื้นฐานแล้วมันเป็นแบบอะนาล็อกกับ imagesLaded แต่ก็ใช้ได้กับ srcsets ด้วย สิ่งที่ฉันกำลังมองหา! ปลั๊กอินที่ยอดเยี่ยม!
Fabian Schöner

48

$(window).load()จะใช้งานได้เฉพาะในครั้งแรกที่โหลดหน้าเว็บ หากคุณกำลังทำสิ่งต่าง ๆ แบบไดนามิก (ตัวอย่าง: ปุ่มคลิกรอรูปใหม่ที่จะโหลด) สิ่งนี้จะไม่ทำงาน เพื่อให้บรรลุนั้นคุณสามารถใช้ปลั๊กอินของฉัน:

การสาธิต

ดาวน์โหลด

/**
 *  Plugin which is applied on a list of img objects and calls
 *  the specified callback function, only when all of them are loaded (or errored).
 *  @author:  H. Yankov (hristo.yankov at gmail dot com)
 *  @version: 1.0.0 (Feb/22/2010)
 *  http://yankov.us
 */

(function($) {
$.fn.batchImageLoad = function(options) {
    var images = $(this);
    var originalTotalImagesCount = images.size();
    var totalImagesCount = originalTotalImagesCount;
    var elementsLoaded = 0;

    // Init
    $.fn.batchImageLoad.defaults = {
        loadingCompleteCallback: null, 
        imageLoadedCallback: null
    }
    var opts = $.extend({}, $.fn.batchImageLoad.defaults, options);

    // Start
    images.each(function() {
        // The image has already been loaded (cached)
        if ($(this)[0].complete) {
            totalImagesCount--;
            if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
        // The image is loading, so attach the listener
        } else {
            $(this).load(function() {
                elementsLoaded++;

                if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);

                // An image has been loaded
                if (elementsLoaded >= totalImagesCount)
                    if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
            });
            $(this).error(function() {
                elementsLoaded++;

                if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);

                // The image has errored
                if (elementsLoaded >= totalImagesCount)
                    if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
            });
        }
    });

    // There are no unloaded images
    if (totalImagesCount <= 0)
        if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
};
})(jQuery);

ในกรณีที่ใครต้องการตัวอย่างการใช้งานปลั๊กอิน BatchImagesLoad: yankov.us/batchImageLoad
Jonathan Marzullo

1
ฉันหมายถึงไม่มีการดูหมิ่น แต่ไม่มีใครเชื่อถือ "เพียงแค่" ในคำพูดของคุณเกี่ยวกับความน่าเชื่อถือของปลั๊กอินของคุณ ตามที่ระบุไว้ในYevgeniy Afanasyevคำตอบ 's , imagesLoaded ไม่ได้งานที่ดีมากที่นี้และครอบคลุมกรณีการใช้งานที่คุณกล่าวถึงพร้อมกับหลาย ๆ กรณีมุมอื่น ๆ(ดูประเด็น GitHub แก้ไข)
Adrien เป็น

19

สำหรับผู้ที่ต้องการได้รับแจ้งการดาวน์โหลดภาพเดียวที่ได้รับการร้องขอหลังจาก$(window).loadไฟไหม้คุณสามารถใช้loadเหตุการณ์ขององค์ประกอบภาพ

เช่น:

// create a dialog box with an embedded image
var $dialog = $("<div><img src='" + img_url + "' /></div>");

// get the image element (as a jQuery object)
var $imgElement = $dialog.find("img");

// wait for the image to load 
$imgElement.load(function() {
    alert("The image has loaded; width: " + $imgElement.width() + "px");
});

13

ยังไม่มีคำตอบใดที่ให้สิ่งที่ดูเหมือนจะเป็นคำตอบที่ง่ายที่สุด

$('#image_id').load(
  function () {
    //code here
});

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

6

ฉันจะแนะนำให้ใช้imagesLoaded.jsไลบรารี javascript

ทำไมไม่ใช้ของ jQuery $(window).load()?

ในฐานะที่เป็น ansered บน/programming/26927575/why-use-imagesloaded-javascript-library-versus-jquerys-window-load/26929951

มันเป็นเรื่องของขอบเขต imagesLoaded ช่วยให้คุณกำหนดเป้าหมายชุดของรูปภาพในขณะที่$(window).load()กำหนดเป้าหมายสินทรัพย์ทั้งหมด- รวมถึงรูปภาพ, วัตถุ, .js และ. css ทั้งหมดและแม้กระทั่ง iframes เป็นไปได้มากที่สุดที่ ImagesLoaded จะเรียกใช้เร็วกว่า$(window).load()เพราะมีการกำหนดเป้าหมายเป็นชุดเนื้อหาขนาดเล็ก

เหตุผลที่ดีอื่น ๆ ในการใช้ imagesloaded

  • สนับสนุนอย่างเป็นทางการโดย IE8 +
  • ใบอนุญาต: MIT ใบอนุญาต
  • การพึ่งพา: ไม่มี
  • น้ำหนัก (ลดขนาด & gzipped): 7kb ลดขนาด (แสง!)
  • ตัวสร้างการดาวน์โหลด (ช่วยในการลดน้ำหนัก): ไม่จำเป็นต้องมีขนาดเล็กอยู่แล้ว
  • บน Github: ใช่
  • ชุมชนและผู้มีส่วนร่วม: สมาชิกที่มีขนาดใหญ่กว่า 4,000 คน แต่มีผู้ร่วมให้งานเพียง 13 คน
  • ประวัติและการมีส่วนร่วม: เสถียรเหมือนเก่า (ตั้งแต่ปี 2010) แต่ยังคงใช้งานโครงการอยู่

ทรัพยากร


4

ด้วย jQuery ฉันมาพร้อมกับสิ่งนี้ ...

$(function() {
    var $img = $('img'),
        totalImg = $img.length;

    var waitImgDone = function() {
        totalImg--;
        if (!totalImg) alert("Images loaded!");
    };

    $('img').each(function() {
        $(this)
            .load(waitImgDone)
            .error(waitImgDone);
    });
});

การสาธิต: http://jsfiddle.net/molokoloco/NWjDb/


ฉันพบว่าสิ่งนี้จะทำงานไม่ถูกต้องหากเบราว์เซอร์ส่งคืน 304 การตอบกลับที่ไม่ใช่โมฆะสำหรับภาพซึ่งหมายความว่าภาพนั้นถูกแคช
JohnyFree

1

ใช้ imagesLoaded PACKAGED v3.1.8 (6.8 Kb เมื่อย่อเล็กสุด) มันค่อนข้างเก่า (ตั้งแต่ปี 2010) แต่ยังคงใช้งานโครงการ

คุณสามารถค้นหาได้ใน github: https://github.com/desandro/imagesloaded

เว็บไซต์อย่างเป็นทางการของพวกเขา: http://imagesloaded.desandro.com/

ทำไมมันถึงดีกว่าการใช้:

$(window).load() 

เพราะคุณอาจต้องการโหลดภาพแบบไดนามิกเช่นนี้jsfiddle

$('#button').click(function(){
    $('#image').attr('src', '...');
});

1
ที่จริงแล้ว imagesloaded ไม่รองรับการเปลี่ยนแปลงค่า src attribute ข้ามเบราว์เซอร์ คุณต้องสร้างองค์ประกอบภาพใหม่ทุกครั้ง ลองใช้กับ Firefox แล้วคุณจะเห็นปัญหาปรากฏขึ้น
Adrien เป็น

จุดดีฉันเพิ่งทดสอบกับ Google chrome และ IE-11 เท่านั้น มันทำงานอยู่ ขอบคุณ
Yevgeniy Afanasyev

ฉันได้เพิ่มปัญหาข้ามเบราว์เซอร์ในคำถามของฉัน stackoverflow.com/q/26927575 ในจุด "สิ่งที่คุณไม่สามารถทำกับ imagesloaded" ดูปัญหา imagesLoaded ที่เกี่ยวข้องใน Github github.com/desandro/imagesloaded/issues/121
Adrien เป็น

1

วิธีนี้คุณสามารถดำเนินการกระทำเมื่อโหลดรูปภาพทั้งหมดภายในร่างกายหรือคอนเทนเนอร์อื่น ๆ (ซึ่งขึ้นอยู่กับการเลือกของคุณ) PQUQUERY บริสุทธิ์ไม่จำเป็นต้องมี pluggins

var counter = 0;
var size = $('img').length;

$("img").load(function() { // many or just one image(w) inside body or any other container
    counter += 1;
    counter === size && $('body').css('background-color', '#fffaaa'); // any action
}).each(function() {
  this.complete && $(this).load();        
});

0

วิธีการแก้ปัญหาของฉันคือคล้ายกับmolokoloco เขียนเป็นฟังก์ชัน jQuery:

$.fn.waitForImages = function (callback) {
    var $img = $('img', this),
        totalImg = $img.length;

    var waitImgLoad = function () {
        totalImg--;
        if (!totalImg) {
            callback();
        }
    };

    $img.each(function () {
        if (this.complete) { 
            waitImgLoad();
        }
    })

    $img.load(waitImgLoad)
        .error(waitImgLoad);
};

ตัวอย่าง:

<div>
    <img src="img1.png"/>
    <img src="img2.png"/>
</div>
<script>
    $('div').waitForImages(function () {
        console.log('img loaded');
    });
</script>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.