Forma oficial de pedirle a jQuery que espere a que se carguen todas las imágenes antes de ejecutar algo


641

En jQuery cuando haces esto:

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

Espera a que el DOM se cargue y ejecuta su código. Si no se cargan todas las imágenes, aún ejecuta el código. Obviamente, esto es lo que queremos si estamos inicializando cualquier elemento DOM, como mostrar u ocultar elementos o adjuntar eventos.

Digamos, sin embargo, que quiero algo de animación y no quiero que se ejecute hasta que se carguen todas las imágenes. ¿Hay alguna forma oficial en jQuery para hacer esto?

La mejor manera que tengo es usar <body onload="finished()">, pero realmente no quiero hacerlo a menos que tenga que hacerlo.

Nota: Hay un error en jQuery 1.3.1 en Internet Explorer que realmente espera a que se carguen todas las imágenes antes de ejecutar el código en su interior $function() { }. Entonces, si está utilizando esa plataforma, obtendrá el comportamiento que estoy buscando en lugar del comportamiento correcto descrito anteriormente.


3
no $("img").load()funciona
Lucas

1
Creo que vale la pena mencionar que si establece los atributos de las dimensiones, puede ejecutar de forma segura algún código en la función listo que se basa en esas dimensiones. Con php puede capturarlos con php.net/manual/en/function.getimagesize.php al cargarlos para almacenarlos en db o antes de enviarlos al navegador.
Alqin

si desea que algo haga un trabajo increíble, consulte la biblioteca javascript cargada de imágenes extremadamente buena y popular mencionada en esta respuesta a continuación stackoverflow.com/a/26458347/759452
Adrien Be

"Aquí vine a buscar cualquier cosa, excepto una forma oficial".
Léon Pelletier

Respuestas:


1035

Con jQuery, se usa $(document).ready()para ejecutar algo cuando se carga el DOM y $(window).on("load", handler)para ejecutar algo cuando se cargan todas las demás cosas, como las imágenes.

La diferencia se puede ver en el siguiente archivo HTML completo, siempre que tenga jollyrogerarchivos JPEG (u otros adecuados):

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

Con eso, el cuadro de alerta aparece antes de cargar las imágenes, porque el DOM está listo en ese punto. Si luego cambias:

$(document).ready(function() {

dentro:

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

a continuación, el cuadro de alerta no aparece hasta después de las imágenes se cargan.

Por lo tanto, para esperar hasta que toda la página esté lista, puede usar algo como:

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

32
golpea la frente +1 lo olvidé por completo. $ (ventana) .load () no se disparará hasta que se terminen las imágenes.
Paolo Bergantino

10
Yo hice lo mismo. Incluso, lea una respuesta sin saber que era yo y todavía no la entiendo.
Rimian

24
Solo una nota: esto no parece funcionar con Chromium (y supongo que Chrome). El evento $ (window) .ready parece activarse igual que $ (document) .ready, antes de que se completen las imágenes.
Nathan Crause

24
pero es $ (ventana) .load (function ())
TJ-

3
@KyorCode ¿Estás seguro de que no es solo porque las imágenes en IE se almacenaron en caché? Si eso sucede, no dispararán un evento de "carga" en absoluto. Este artículo ayuda a solucionar este problema.
Jamie Barker

157

Escribí un complemento que puede disparar devoluciones de llamada cuando las imágenes se han cargado en elementos, o disparar una vez por imagen cargada.

Es similar a $(window).load(function() { .. }), excepto que le permite definir cualquier selector para verificar. Si solo desea saber cuándo se #contenthan cargado todas las imágenes (por ejemplo), este es el complemento para usted.

También es compatible con la carga de imágenes que se hace referencia en el CSS, tales como background-image, list-style-image, etc.

waitForImages jQuery plugin

Ejemplo de uso

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

Ejemplo en jsFiddle .

Hay más documentación disponible en la página de GitHub.


1
¡¡Gracias!! $ .load () no funcionaba para mí, pero esto funciona perfectamente.
Fraxtil

Utilizo Chrome Versión 22.0.1229.94 y este complemento, e intenté leer los desplazamientos de las imágenes cargadas dentro de waitFormImages: ('img selector').each(function(index) { var offset = $(this).offset(); ...});sin embargo, offset.top sigue siendo cero. ¿Por qué?
basZero

1
@basZero Difícil de distinguir sin más contexto. Plantee un problema en la página Problemas .
alex

No funciona para mí cuando las imágenes se combinan. ¿Alguien tiene una solución para esto?
Mandeep Jain

2
Es básicamente análogo a imagesLoaded pero también funciona con srcsets. ¡Exactamente lo que estaba buscando! ¡Gran complemento!
Fabian Schöner

48

$(window).load()funcionará solo la primera vez que se cargue la página. Si está haciendo cosas dinámicas (ejemplo: haga clic en el botón, espere a que se carguen algunas imágenes nuevas), esto no funcionará. Para lograr eso, puedes usar mi complemento:

Manifestación

Descargar

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

por si alguien necesita un ejemplo de uso del complemento BatchImagesLoad
Jonathan Marzullo

1
No quiero faltarle al respeto, pero uno no puede confiar "solo" en su palabra con respecto a la confiabilidad de su complemento. Como se menciona en Yevgeniy Afanasyevla respuesta , imagesLoaded hace un trabajo mucho mejor en esto y cubre el caso de uso que mencionó junto con muchos otros casos de esquina (vea los problemas resueltos de github) .
Adrien Be

19

Para aquellos que desean ser notificados de la finalización de la descarga de una sola imagen que se solicita después de los $(window).loadincendios, puede usar el loadevento del elemento de imagen .

p.ej:

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

Ninguna de las respuestas hasta ahora ha dado lo que parece ser la solución más simple.

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

Lo bueno de esto es que puede hacer que se active para imágenes individuales tan pronto como se carguen.
Top Cat

6

Recomendaría usar la imagesLoaded.jsbiblioteca javascript.

¿Por qué no usar jQuery's $(window).load()?

Según lo publicado en /programming/26927575/why-use-imagesloaded-javascript-library-versus-jquerys-window-load/26929951

Es una cuestión de alcance. imagesLoaded le permite apuntar a un conjunto de imágenes, mientras que $(window).load()apunta a todos los activos , incluidas todas las imágenes, objetos, archivos .js y .css e incluso iframes. Lo más probable es que imagesLoaded se active más pronto que $(window).load()porque apunta a un conjunto más pequeño de activos.

Otras buenas razones para usar imágenes cargadas

  • oficialmente compatible con IE8 +
  • licencia: Licencia MIT
  • dependencias: ninguna
  • peso (minificado y comprimido): 7 kb minificado (¡ligero!)
  • generador de descargas (ayuda a reducir el peso): no es necesario, ya es pequeño
  • en Github: SÍ
  • comunidad y contribuyentes: bastante grande, más de 4000 miembros, aunque solo 13 contribuyentes
  • historia y contribuciones: estable como proyecto relativamente antiguo (desde 2010) pero todavía activo

Recursos


4

Con jQuery vengo con esto ...

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

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

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

Demostración: http://jsfiddle.net/molokoloco/NWjDb/


Descubrí que esto no funcionará correctamente si el navegador devuelve la respuesta 304 No modificada para la imagen, lo que significa que la imagen está en caché.
JohnyFree

1

Use imagesLoaded PACKAGED v3.1.8 (6.8 Kb cuando está minimizado). Es un proyecto relativamente antiguo (desde 2010) pero aún activo.

Puede encontrarlo en github: https://github.com/desandro/imagesloaded

Su sitio oficial: http://imagesloaded.desandro.com/

Por qué es mejor que usar:

$(window).load() 

Porque es posible que desee cargar imágenes dinámicamente, así: jsfiddle

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

1
En realidad, las imágenes cargadas no admiten el cambio del valor del atributo src en el navegador cruzado. Debe crear un nuevo elemento de imagen cada vez. Pruébelo en Firefox y verá aparecer el problema.
Adrien Be

Buen punto, solo he probado en Google Chrome e IE-11 todavía. Estaba funcionando. Gracias.
Yevgeniy Afanasyev

Agregué este problema de navegador cruzado en mi pregunta stackoverflow.com/q/26927575 en el punto "Lo que no se puede hacer con las imágenes cargadas", vea las imágenes Problema relevante cargado en Github github.com/desandro/imagesloaded/issues/121
Adrien Será el

1

De esta manera, puede ejecutar una acción cuando se cargan todas las imágenes dentro del cuerpo o cualquier otro contenedor (que depende de su selección). PURE JQUERY, no se necesitan complementos.

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

Mi solución es similar al molokoloco . Escrito como función 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);
};

ejemplo:

<div>
    <img src="img1.png"/>
    <img src="img2.png"/>
</div>
<script>
    $('div').waitForImages(function () {
        console.log('img loaded');
    });
</script>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.