Comment puis-je déterminer si une image a été chargée, en utilisant Javascript / jQuery?

85

J'écris du Javascript pour redimensionner la grande image pour l'adapter à la fenêtre du navigateur de l'utilisateur. (Je ne contrôle malheureusement pas la taille des images sources.)

Donc, quelque chose comme ça serait dans le HTML:

<img id="photo"
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Existe-t-il un moyen pour moi de déterminer si l' srcimage d'une imgbalise a été téléchargée?

J'en ai besoin car je rencontre un problème s'il $(document).ready()est exécuté avant que le navigateur n'ait chargé l'image. $("#photo").width()et $("#photo").height()renverra la taille de l'espace réservé (le texte alternatif). Dans mon cas, c'est quelque chose comme 134 x 20.

Pour le moment, je vérifie simplement si la hauteur de la photo est inférieure à 150 et en supposant que si c'est le cas, il ne s'agit que d'un texte alternatif. Mais c'est tout un hack, et cela se casserait si une photo mesure moins de 150 pixels de haut (ce qui n'est probablement pas le cas dans mon cas particulier), ou si le texte alternatif mesure plus de 150 pixels de haut (cela pourrait éventuellement se produire sur une petite fenêtre de navigateur) .


Edit: Pour tous ceux qui souhaitent voir le code:

$(function()
{
  var REAL_WIDTH = $("#photo").width();
  var REAL_HEIGHT = $("#photo").height();

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()
  {
    if(REAL_HEIGHT < 150)
    {
      REAL_WIDTH = $("#photo").width();
      REAL_HEIGHT = $("#photo").height();
      if(REAL_HEIGHT < 150)
      {
        //image not loaded.. try again in a quarter-second
        setTimeout(adjust_photo_size, 250);
        return;
      }
    }

    var new_width = . . . ;
    var new_height = . . . ;

    $("#photo").width(Math.round(new_width));
    $("#photo").height(Math.round(new_height));
  }

});

Mise à jour : Merci pour les suggestions. Il y a un risque que l'événement ne soit pas déclenché si je définis un rappel pour l' $("#photo").loadévénement, j'ai donc défini un événement onLoad directement sur la balise image. Pour mémoire, voici le code avec lequel j'ai fini par aller:

<img id="photo"
     onload="photoLoaded();"
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Puis en Javascript:

//This must be outside $() because it may get called first
var isPhotoLoaded = false;
function photoLoaded()
{
  isPhotoLoaded = true;
}

$(function()
{
  //Hides scrollbars, so we can resize properly.  Set with JS instead of
  //  CSS so that page doesn't break with JS disabled.
  $("body").css("overflow", "hidden");

  var REAL_WIDTH = -1;
  var REAL_HEIGHT = -1;

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()
  {
    if(!isPhotoLoaded)
    {
      //image not loaded.. try again in a quarter-second
      setTimeout(adjust_photo_size, 250);
      return;
    }
    else if(REAL_WIDTH < 0)
    {
      //first time in this function since photo loaded
      REAL_WIDTH = $("#photo").width();
      REAL_HEIGHT = $("#photo").height();
    }

    var new_width = . . . ;
    var new_height = . . . ;

    $("#photo").width(Math.round(new_width));
    $("#photo").height(Math.round(new_height));
  }

});
Kip
la source
1
C'est si vieux et vous avez déjà accepté une réponse, alors je vais juste commenter ici. Pourquoi ne pouvez-vous pas utiliser le plugin jQuery 'onImagesLoad'? Et aussi, jQuery ou pas, quel est le problème avec le réglage max-widthet max-heightle style de l'image avec Javascript? Vous évitez alors TOUT le code que vous avez dû écrire en définissant la largeur / hauteur maximale sur la taille de la largeur / hauteur de la fenêtre.
@ jon.wd7: je ne suis pas familier avec ce plugin, et il n'a peut-être pas existé en 2008. quant à max-width et max-height, deux choses: 1) ils ne sont pas pris en charge dans IE (enfin je ne suis pas sûr d'IE 8); 2) si la fenêtre change de taille (la fenêtre est redimensionnée, etc.) alors j'aurais toujours besoin de javascript pour changer la largeur max / hauteur max (bien que je ne puisse pas si j'ai utilisé "100%" plutôt qu'une mesure de pixels)
Kip du
Il est définitivement pris en charge dans IE7 et IE8, selon quirksmode.org. Je ne suis donc pas sûr de votre problème. Personnellement, je ne supporte pas IE6 pour de petites choses comme celle-ci, donc ce qu'ils verront est la même chose qu'un utilisateur sans JS activé verrait. Et bien sûr, vous devrez réinitialiser max-widthet max-heightredimensionner. Mais c'est une tâche assez facile, une seule ligne utilisant .resize()en fait.
3
La propriété complete donne le moyen impératif de savoir si l'image a été chargée.
BorisOkunskiy
1
@Adrien, Mozilla affiche maintenant complet comme pris en charge par tous les principaux navigateurs, à l'exception d'Andoid (inconnu).
Oliver Bock

Réponses:

33

Ajoutez un écouteur d'événement ou demandez à l'image de s'annoncer avec onload. Ensuite, déterminez les dimensions à partir de là.

<img id="photo"
     onload='loaded(this.id)'
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />
Diodeus - James MacFarlane
la source
Selon les spécifications, onload n'est qu'un événement pour les éléments body et frameset; Cela dit, je pense que cela fonctionne dans IE, mais je ne sais pas si cela fonctionne dans d'autres navigateurs ou que c'est quelque chose que vous pouvez supposer ... J'étais juste en train de regarder cela il y a quelques semaines ...
Jason Bunting
Je l'ai testé dans IE6, IE7, FF3, Opera9, Safair (Windows Beta) et Chrome (Windows Beta).
Kip
9
Les comportements et contenus désordonnés sont découragés. Les événements doivent être appliqués en utilisant Javascript, pas en HTML.
dionyziz
10
Son commentaire est pertinent puisque nous ne sommes pas coincés en 2008. Les gens lisent encore ceci, et même si ce n'était pas considéré comme une mauvaise pratique en 08, vous ne voulez pas que les gens pensent que c'est une bonne pratique maintenant.
Spoeken
3
document.querySelector ("img"). addEventListener ("charger", function () {alert ('onload!');});
Frank Schwieterman
14

En utilisant le magasin de données jquery, vous pouvez définir un état «chargé».

<img id="myimage" onload="$(this).data('loaded', 'loaded');" src="lolcats.jpg" />

Ensuite, vous pouvez faire ailleurs:

if ($('#myimage').data('loaded')) {
    // loaded, so do stuff
}
Mike Fogel
la source
2
Utilisez à la jQuery(this)place de $(this)pour une meilleure compatibilité avec d'autres bibliothèques (jquery ne possède pas le $), en particulier lorsque vous avez JavaScript en html.
John Magnolia
11

La bonne réponse est d'utiliser event.special.load

Il est possible que l'événement de chargement ne soit pas déclenché si l'image est chargée à partir du cache du navigateur. Pour tenir compte de cette possibilité, nous pouvons utiliser un événement de chargement spécial qui se déclenche immédiatement si l'image est prête. event.special.load est actuellement disponible en tant que plugin.

Par la documentation sur .load ()

Evan Carroll
la source
2
J'allais ajouter une réponse avec une suggestion comme celle-ci, heureux d'avoir vu cette réponse avant de la coder. Fondamentalement, vos gestionnaires doivent d'abord vérifier si l'image est chargée avant de définir le gestionnaire. S'il est déjà chargé, lancez le rappel immédiatement. C'est ce que $.readyfait. J'allais suggérer de simplement vérifier la largeur, mais cela a ses problèmes, j'aime vraiment cette solution.
Juan Mendes
5

Vous voulez faire ce qu'Allain a dit, mais sachez que parfois l'image se charge avant que dom ready, ce qui signifie que votre gestionnaire de charge ne se déclenchera pas. Le meilleur moyen est de faire comme le dit Allain, mais définissez le src de l'image avec javascript après avoir attaché le load hander. De cette façon, vous pouvez garantir qu'il se déclenche.

En termes d'accessibilité, votre site fonctionnera-t-il toujours pour les personnes sans javascript? Vous pouvez donner à la balise img le bon src, attacher votre gestionnaire prêt pour exécuter votre js: effacez l'image src (donnez-lui une hauteur fixe avec et une hauteur avec css pour empêcher le scintillement de la page), puis définissez votre gestionnaire de chargement img, puis réinitialisez le src sur le fichier correct. De cette façon, vous couvrez toutes les bases :)

Andrew Bullock
la source
Le site fonctionne toujours pour les personnes sans Javascript, il leur suffit de faire défiler pour voir toute l'image.
Kip
4

Selon l'un des commentaires récents à votre question initiale

$(function() {

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()  {
    if (!$("#photo").get(0).complete) {
       $("#photo").load(function() {
          adjust_photo_size();
       });
    } else {
      ... 
    }
});

Avertissement Cette réponse pourrait provoquer une boucle sérieuse dans ie8 et les versions antérieures, car img.complete n'est pas toujours correctement paramétré par le navigateur. Si vous devez prendre en charge ie8, utilisez un indicateur pour vous rappeler que l'image est chargée.

grand brochet
la source
Le tenir. Cette réponse pourrait provoquer une boucle sérieuse dans ie8 et les versions antérieures, car img.complete n'est pas toujours correctement défini par le navigateur. Si vous devez prendre en charge ie8, utilisez un indicateur pour vous rappeler que l'image est chargée.
commonpike
2

Essayez quelque chose comme:

$("#photo").load(function() {
    alert("Hello from Image");
});
Allain Lalonde
la source
6
Merci. Cependant, il est possible que l'image ait déjà été chargée avant que cela ne se produise, auquel cas l'événement de chargement ne serait pas déclenché.
Kip
Que diriez-vous d'une balise de script définissant cet événement juste après la balise d'image? La raison d'utiliser ready est de s'assurer que tout le document est chargé, ce qui n'est pas nécessaire dans ce cas, non?
Jason Goemaat
2

Il existe un plugin jQuery appelé "imagesLoaded" qui fournit une méthode compatible avec tous les navigateurs pour vérifier si l'image ou les images d'un élément ont été chargées.

Site: https://github.com/desandro/imagesloaded/

Utilisation pour un conteneur contenant de nombreuses images:

$('container').imagesLoaded(function(){
 console.log("I loaded!");
})

Le plugin est génial:

  1. fonctionne pour vérifier un conteneur avec de nombreuses images à l'intérieur
  2. fonctionne pour vérifier une image pour voir si elle a été chargée
geai
la source
semble un peu lourd 5KB minifié uniquement pour vérifier img chargé. Devrait être une méthode plus simple et plus légère disponible ...
cdalxndr
1

Des commentaires sur celui-ci?

...

doShow = function(){
  if($('#img_id').attr('complete')){
    alert('Image is loaded!');
  } else {
    window.setTimeout('doShow()',100);
  }
};

$('#img_id').attr('src','image.jpg');

doShow();

...

On dirait que ça marche partout ...

Geai
la source
c'est une mauvaise pratique à utilisersetTimeout
cdalxndr
1

Je viens de créer une fonction jQuery pour charger une image à l'aide de jQuerys Deferred Object, ce qui permet de réagir très facilement à un événement de chargement / erreur:

$.fn.extend({
    loadImg: function(url, timeout) {
        // init deferred object
        var defer = $.Deferred(),
            $img = this,
            img = $img.get(0),
            timer = null;

        // define load and error events BEFORE setting the src
        // otherwise IE might fire the event before listening to it
        $img.load(function(e) {
            var that = this;
            // defer this check in order to let IE catch the right image size
            window.setTimeout(function() {
                // make sure the width and height are > 0
                ((that.width > 0 && that.height > 0) ? 
                    defer.resolveWith : 
                    defer.rejectWith)($img);
            }, 1);
        }).error(function(e) {
            defer.rejectWith($img);
        });

        // start loading the image
        img.src = url;

        // check if it's already in the cache
        if (img.complete) {
            defer.resolveWith($img);
        } else if (0 !== timeout) {
            // add a timeout, by default 15 seconds
            timer = window.setTimeout(function() {
                defer.rejectWith($img);
            }, timeout || 15000);
        }

        // return the promise of the deferred object
        return defer.promise().always(function() {
            // stop the timeout timer
            window.clearTimeout(timer);
            timer = null;
            // unbind the load and error event
            this.off("load error");
        });
    }
});

Usage:

var image = $('<img />').loadImg('http://www.google.com/intl/en_com/images/srpr/logo3w.png')
.done(function() {
    alert('image loaded');
    $('body').append(this);
}).fail(function(){
    alert('image failed');
});

Voyez-le fonctionner sur: http://jsfiddle.net/roberkules/AdWZj/

roberkules
la source
Ça a l'air formidable. Pouvez-vous s'il vous plaît donner un exemple exact de quand votre code est préférable à img.onload et img.onerror? Votre code est-il uniquement destiné à gérer les lacunes apparentes de la gestion des erreurs jQuery dont je viens d'être informé: cette erreur ne se déclenche pas dans IE s'il n'y a pas d'extension de fichier?
mplungjan
idée intéressante. alors savoir quand l'image a fait son facile. Mais que se passerait-il si l'image ne pouvait pas être chargée. Je cherchais un moyen de savoir si le chargement de l'image a échoué. et vous m'avez donné l'idée d'un délai d'attente lors du chargement. +1 pour cela
chêne
1
@oak le délai d'attente ne doit être qu'une solution de secours. la plupart des navigateurs doivent déclencher un errorévénement géré par .error(function(e) { defer.rejectWith($img); }). Si vous regardez le jsFiddle, vous verrez que le http://www.google.com/abc.png not foundtexte s'affiche immédiatement dans le volet des résultats (sans attendre un délai d'attente, car l'événement d'erreur s'est
déclenché
notez que pour que jquery déclenche .error, deux choses doivent être 1. le handle mais être défini avant que l'erreur ne se produise. 2. .error ne gère que le protocole http et non file: // donc vous n'obtiendrez pas d'erreur là-bas ..
oak
dans mon exemple de code, le gestionnaire de réussite / erreur est défini avant d'attribuer l'attribut src exactement pour cette raison. à propos de la file://restriction - je n'ai jamais eu besoin de lier des images en utilisant le protocole de fichier et je ne pense pas qu'il y ait grand besoin.
roberkules
1

Cette fonction vérifie si une image est chargée en fonction de ses dimensions mesurables. Cette technique est utile si votre script s'exécute après que certaines des images ont déjà été chargées.

imageLoaded = function(node) {
    var w = 'undefined' != typeof node.clientWidth ? node.clientWidth : node.offsetWidth;
    var h = 'undefined' != typeof node.clientHeight ? node.clientHeight : node.offsetHeight;
    return w+h > 0 ? true : false;
};
Ralph Ritoch
la source
J'ai découvert que cette solution peut nécessiter qu'il n'y ait pas de marge ou de remplissage sur l'image et que le texte alternatif d'une chaîne vide soit fourni. Dans la plupart des cas cependant, cela fonctionne comme prévu. Il échouera uniquement si la taille de l'image déchargée est supérieure à zéro.
Ralph Ritoch
1

J'ai trouvé que cela fonctionnait pour moi

document.querySelector("img").addEventListener("load", function() { alert('onload!'); });

Le mérite revient entièrement à Frank Schwieterman, qui a commenté la réponse acceptée. J'ai dû mettre ça ici, c'est trop précieux ...

Armand
la source
0

Nous avons développé une page où il a chargé un certain nombre d'images et ensuite effectué d'autres fonctions seulement après le chargement de l'image. C'était un site très fréquenté qui générait beaucoup de trafic. Il semble que le script simple suivant a fonctionné sur pratiquement tous les navigateurs:

$(elem).onload = function() {
    doSomething();
}

MAIS CECI EST UN PROBLÈME POTENTIEL POUR IE9!

Le SEUL navigateur sur lequel nous avons signalé des problèmes est IE9. Ne sommes-nous pas surpris? Il semble que la meilleure façon de résoudre le problème est de ne pas attribuer de src à l'image avant que la fonction de chargement n'ait été définie, comme ceci:

$(elem).onload = function() {
    doSomething();
}
$(elem).attr('src','theimage.png');

Il semble qu'IE 9 ne lancera parfois pas l' onloadévénement pour une raison quelconque. D'autres solutions sur cette page (comme celle d'Evan Carroll, par exemple) ne fonctionnaient toujours pas. Logiquement, cela vérifiait si l'état de chargement était déjà réussi et déclenchait la fonction et si ce n'était pas le cas, définissez le gestionnaire de chargement, mais même lorsque vous faites cela, nous avons démontré en testant que l'image pouvait se charger entre ces deux lignes de js. apparaissant non chargé sur la première ligne, puis chargement avant que le gestionnaire de chargement ne soit défini.

Nous avons constaté que la meilleure façon d'obtenir ce que vous voulez est de ne pas définir le src de l'image tant que vous n'avez pas défini le onloaddéclencheur d'événement.

Nous avons récemment arrêté de prendre en charge IE8, donc je ne peux pas parler des versions antérieures à IE9, sinon, sur tous les autres navigateurs utilisés sur le site - IE10 et 11 ainsi que Firefox, Chrome, Opera, Safari et autres les navigateurs mobiles utilisaient - définir le srcavant d'attribuer le onloadgestionnaire n'était même pas un problème.

Poulpe
la source
0

Puis-je suggérer une solution CSS pure?

Ayez juste une Div dans laquelle vous voulez montrer l'image. Définissez l'image comme arrière-plan. Alors ayez la propriété background-size: coverou background-size: containselon la façon dont vous la voulez.

coverrecadrera l'image jusqu'à ce que les petits côtés recouvrent la boîte. containgardera l'image entière à l'intérieur du div, vous laissant des espaces sur les côtés.

Consultez l'extrait ci-dessous.

div {
  height: 300px;
  width: 300px;
  border: 3px dashed grey;
  background-position: center;
  background-repeat: no-repeat;
}

.cover-image {
  background-size: cover;
}

.contain-image {
  background-size: contain;
}
<div class="cover-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>
<br/>
<div class="contain-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>

souriante
la source
0

Je trouve que cette solution simple fonctionne le mieux pour moi:

        function setEqualHeight(a, b) {
            if (!$(a).height()) {
                return window.setTimeout(function(){ setEqualHeight(a, b); }, 1000);
            }
            $(b).height($(a).height());
        }

        $(document).ready(function() {
            setEqualHeight('#image', '#description');
            $(window).resize(function(){setEqualHeight('#image', '#description')});
        });
    </script>
Martin Francis
la source