Manière officielle de demander à jQuery d'attendre que toutes les images se chargent avant d'exécuter quelque chose

641

Dans jQuery lorsque vous faites cela:

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

Il attend que le DOM se charge et exécute votre code. Si toutes les images ne sont pas chargées, il exécute toujours le code. C'est évidemment ce que nous voulons si nous initialisons des éléments DOM tels que l'affichage ou le masquage d'éléments ou l'attachement d'événements.

Disons cependant que je veux une animation et je ne veux pas qu'elle s'exécute tant que toutes les images ne sont pas chargées. Existe-t-il un moyen officiel dans jQuery de le faire?

La meilleure façon dont je dispose est de l'utiliser <body onload="finished()">, mais je ne veux vraiment le faire que si je le dois.

Remarque: Il existe un bogue dans jQuery 1.3.1 dans Internet Explorer qui attend en fait que toutes les images se chargent avant d'exécuter du code à l'intérieur $function() { }. Donc, si vous utilisez cette plate-forme, vous obtiendrez le comportement que je recherche au lieu du comportement correct décrit ci-dessus.

Simon_Weaver
la source
3
ne $("img").load()fonctionne pas ?
Lucas
1
Je pense qu'il vaut la peine de mentionner que si vous définissez les attributs de dimensions, vous pouvez exécuter en toute sécurité du code dans une fonction prête qui repose sur ces dimensions. Avec php, vous pouvez les récupérer avec php.net/manual/en/function.getimagesize.php lors du téléchargement pour les stocker dans db ou avant leur sortie sur le navigateur.
Alqin
si vous voulez que quelque chose fasse un travail incroyable, alors consultez la bibliothèque javascript extrêmement chargée et très populaire mentionnée dans cette réponse stackoverflow.com/a/26458347/759452
Adrien Be
"Ici, je suis venu pour trouver autre chose qu'une manière officielle."
Léon Pelletier

Réponses:

1035

Avec jQuery, vous utilisez $(document).ready()pour exécuter quelque chose lorsque le DOM est chargé et $(window).on("load", handler)pour exécuter quelque chose lorsque toutes les autres choses sont également chargées, telles que les images.

La différence peut être vue dans le fichier HTML complet suivant, à condition que vous ayez un jollyrogerfichier JPEG (ou d'autres fichiers appropriés):

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

Avec cela, la boîte d'alerte apparaît avant le chargement des images, car le DOM est prêt à ce stade. Si vous changez ensuite:

$(document).ready(function() {

dans:

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

alors la boîte d'alerte n'apparaît qu'après le chargement des images.

Par conséquent, pour attendre que la page entière soit prête, vous pouvez utiliser quelque chose comme:

$(window).on("load", function() {
    // weave your magic here.
});
paxdiablo
la source
32
claque le front +1 a totalement oublié cela. $ (window) .load () ne se déclenchera pas tant que les images ne seront pas terminées.
Paolo Bergantino
10
J'ai fait pareil. Même, lisez une réponse ne sachant pas que c'était moi et ne la comprenant toujours pas.
Rimian
24
Juste une note - cela ne semble pas fonctionner sous Chromium (et je suppose que Chrome). L'événement $ (window) .ready semble se déclencher de la même manière que $ (document) .ready - avant que les images ne soient terminées.
Nathan Crause
24
mais c'est $ (window) .load (function ())
TJ-
3
@KyorCode Êtes-vous sûr que ce n'est pas seulement parce que les images dans IE ont été mises en cache? Si cela se produit, ils ne déclencheront pas du tout un événement de "chargement". Cet article permet de contourner ce problème.
Jamie Barker
157

J'ai écrit un plugin qui peut déclencher des rappels lorsque les images se sont chargées dans les éléments, ou se déclencher une fois par image chargée.

Il est similaire à $(window).load(function() { .. }), sauf qu'il vous permet de définir n'importe quel sélecteur à vérifier. Si vous voulez seulement savoir quand toutes les images #content(par exemple) ont été chargées, c'est le plugin pour vous.

Il prend également en charge le chargement des images référencées dans le CSS, par exemple background-image, list-style-image, etc.

Le plugin waitForImages jQuery

Exemple d'utilisation

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

Exemple sur jsFiddle .

Plus de documentation est disponible sur la page GitHub.

alex
la source
1
Je vous remercie!! $ .load () ne fonctionnait pas pour moi, mais cela fait parfaitement l'affaire.
Fraxtil
J'utilise Chrome Version 22.0.1229.94 et ce plugin, et j'ai essayé de lire les décalages des images chargées dans waitFormImages: ('img selector').each(function(index) { var offset = $(this).offset(); ...});cependant, offset.top est toujours nul. Pourquoi?
basZero
1
@basZero Difficile à dire sans plus de contexte. Veuillez soulever un problème sur la page Problèmes .
alex
Cela ne fonctionne pas pour moi lorsque les images sont cahced. Est-ce que any1 a une solution de contournement pour cela?
Mandeep Jain
2
Son fondamentalement analogue aux images est chargé, mais il fonctionne également avec les ensembles de srcs. Exactement ce que je cherchais! Super plugin!
Fabian Schöner
48

$(window).load()ne fonctionnera que la première fois que la page sera chargée. Si vous faites des choses dynamiques (exemple: cliquez sur le bouton, attendez que de nouvelles images soient chargées), cela ne fonctionnera pas. Pour y parvenir, vous pouvez utiliser mon plugin:

Démo

Télécharger

/**
 *  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);
Roko C. Buljan
la source
juste au cas où quelqu'un aurait besoin d'un exemple d'utilisation du plugin BatchImagesLoad
Jonathan Marzullo
1
Je ne veux pas manquer de respect, mais on ne peut pas se fier "juste" à votre parole concernant la fiabilité de votre plugin. Comme mentionné dans Yevgeniy Afanasyevla réponse de , imagesLoaded fait un bien meilleur travail à ce sujet et couvre le cas d'utilisation que vous avez mentionné ainsi que de nombreux autres cas d'angle (voir les problèmes de github résolus) .
Adrien Be
19

Pour ceux qui souhaitent être informés de la fin du téléchargement d'une seule image qui est demandée après les $(window).loadincendies, vous pouvez utiliser l' loadévénement de l'élément image .

par exemple:

// 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");
});
Dan Passaro
la source
13

Jusqu'à présent, aucune des réponses n'a donné ce qui semble être la solution la plus simple.

$('#image_id').load(
  function () {
    //code here
});
Coz
la source
Ce qui est bien, c'est que vous pouvez le déclencher pour des images individuelles dès qu'elles se chargent.
Top Cat
6

Je recommanderais d'utiliser la imagesLoaded.jsbibliothèque javascript.

Pourquoi ne pas utiliser jQuery $(window).load()?

Comme répondu sur /programming/26927575/why-use-imagesloaded-javascript-library-versus-jquerys-window-load/26929951

C'est une question de portée. imagesLoaded vous permet de cibler un ensemble d'images, tandis que $(window).load()cible tous les actifs - y compris toutes les images, les objets, les fichiers .js et .css, et même les iframes. Très probablement, imagesLoaded se déclenchera plus tôt que $(window).load()parce qu'il cible un plus petit ensemble d'actifs.

Autres bonnes raisons d'utiliser des images chargées

  • officiellement soutenu par IE8 +
  • licence: MIT License
  • dépendances: aucune
  • poids (minifié et gzippé): 7kb minifié (léger!)
  • constructeur de téléchargement (aide à réduire le poids): pas besoin, déjà minuscule
  • sur Github: OUI
  • communauté et contributeurs: assez gros, plus de 4000 membres, bien que seulement 13 contributeurs
  • historique & contributions: stable comme relativement ancien (depuis 2010) mais toujours actif

Ressources

Adrien Be
la source
4

Avec jQuery je viens avec ça ...

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

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

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

Démo: http://jsfiddle.net/molokoloco/NWjDb/

molokoloco
la source
J'ai découvert que cela ne fonctionnera pas correctement si le navigateur renvoie une réponse 304 Non Mofified pour l'image, ce qui signifie que l'image est mise en cache.
JohnyFree
1

Utilisez imagesLoaded PACKAGED v3.1.8 (6,8 Ko lorsqu'il est réduit). C'est un projet relativement ancien (depuis 2010) mais toujours actif.

Vous pouvez le trouver sur github: https://github.com/desandro/imagesloaded

Leur site officiel: http://imagesloaded.desandro.com/

Pourquoi c'est mieux que d'utiliser:

$(window).load() 

Parce que vous voudrez peut-être charger des images dynamiquement, comme ceci: jsfiddle

$('#button').click(function(){
    $('#image').attr('src', '...');
});
Yevgeniy Afanasyev
la source
1
En fait, imagesloaded ne prend pas en charge le changement de navigateur croisé de la valeur d'attribut src. Vous devez créer un nouvel élément d'image à chaque fois. Essayez-le sur Firefox et vous verrez le problème apparaître.
Adrien Be
Bon point, je n'ai encore testé que sur Google Chrome et IE-11. Ça marchait. Merci.
Yevgeniy Afanasyev
J'ai ajouté ce problème de navigateur dans ma question stackoverflow.com/q/26927575 dans le point "Ce que vous ne pouvez pas faire avec les images chargées", voir le problème pertinent imagesLoaded sur Github github.com/desandro/imagesloaded/issues/121
Adrien Soyez
1

De cette façon, vous pouvez exécuter une action lorsque toutes les images à l'intérieur du corps ou de tout autre conteneur (qui dépend de votre sélection) sont chargées. PURE JQUERY, aucun plugin nécessaire.

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();        
});
Mario Medrano
la source
0

Ma solution est similaire à molokoloco . Écrit en tant que fonction 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);
};

exemple:

<div>
    <img src="img1.png"/>
    <img src="img2.png"/>
</div>
<script>
    $('div').waitForImages(function () {
        console.log('img loaded');
    });
</script>
Mariusz Charczuk
la source