Vérifier si une image est chargée (pas d'erreur) avec jQuery

224

J'utilise JavaScript avec la bibliothèque jQuery pour manipuler les vignettes d'images contenues dans une liste non ordonnée. Lorsque l'image est chargée, elle fait une chose, lorsqu'une erreur se produit, elle fait autre chose. J'utilise jQuery load()et les error()méthodes comme événements. Après ces événements, je vérifie l'élément DOM image pour le .complete pour m'assurer que l'image n'était pas déjà chargée avant que jQuery puisse enregistrer les événements.

Cela fonctionne correctement sauf lorsqu'une erreur se produit avant que jQuery puisse enregistrer les événements. La seule solution à laquelle je peux penser est d'utiliser l'imgonerror attribut pour stocker un "indicateur" quelque part dans le monde (ou sur le nœud c'est lui-même) qui dit qu'il a échoué afin que jQuery puisse vérifier que "stocker / nœud" lors de la vérification de .complete.

Quelqu'un a une meilleure solution?

Edit: Points principaux en gras et détails supplémentaires ajoutés ci-dessous: Je vérifie si une image est complète (alias chargée) APRÈS avoir ajouté un événement de chargement et d'erreur sur l'image. De cette façon, si l'image a été chargée avant l'enregistrement des événements, je le saurai encore. Si l'image n'est pas chargée après les événements, les événements s'en occuperont le cas échéant. Le problème est que je peux facilement vérifier si une image est déjà chargée, mais je ne peux pas dire si une erreur s'est produite à la place.

William
la source
Quand enregistrez-vous les événements jQuery? Peut-être que certains codes vous aideront. :)
okw
Il y a beaucoup de code, ce que j'ai dit ci-dessus n'est qu'une version très simple de ce que je fais. J'appelle les événements après le chargement du DOM, une méthode est appelée pour ajouter des événements aux vignettes.
William

Réponses:

250

Une autre option consiste à déclencher les événements onloadet / ou onerroren créant un élément d'image en mémoire et en définissant son srcattribut sur l' srcattribut d'origine de l'image d'origine. Voici un exemple de ce que je veux dire:

$("<img/>")
    .on('load', function() { console.log("image loaded correctly"); })
    .on('error', function() { console.log("error loading image"); })
    .attr("src", $(originalImage).attr("src"))
;

J'espère que cela t'aides!

Xavi
la source
27
Ne semble pas fonctionner aussi bien que je l'espérais. Dans Google Chrome, il semble avoir des problèmes lorsque l'image est déjà dans le cache. Il ne déclenche pas la méthode load (). :(
William
4
Ugg, tu as raison. Chrome est certainement le navigateur le plus ennuyeux à développer. Sur le brillant, je pense que j'ai peut-être trouvé un moyen de contourner le problème: réglez la source d'image sur "" puis revenez à la source d'origine. Je mettrai à jour ma réponse.
Xavi
1
Vous devez mettre la .attrligne après les lignes .loadet .error. Sinon, vous risquez que l'image se charge (ou rencontre une erreur) avant que ces rappels ne soient ajoutés, et ils ne seront pas appelés.
callum
19
@Xavi Chrome n'est pas le navigateur le plus ennuyeux pour lequel développer, essayez de développer pour Internet Explorer 7 ou moins. En plus d'ajouter un paramètre $ _GET à la charge de l'image, chargera une nouvelle image à chaque fois, comme l'a suggéré Gromix.
SSH ce
10
Les méthodes .load()et .error()sont déroutantes et maintenant obsolètes, utilisez .on()et utilisez les événements comme loadet error.
Firsh - LetsWP.io
235

Vérifiez les propriétés completeet naturalWidth, dans cet ordre.

https://stereochro.me/ideas/detecting-broken-images-js

function IsImageOk(img) {
    // During the onload event, IE correctly identifies any images that
    // weren’t downloaded as not complete. Others should too. Gecko-based
    // browsers act like NS4 in that they report this incorrectly.
    if (!img.complete) {
        return false;
    }

    // However, they do have two very useful properties: naturalWidth and
    // naturalHeight. These give the true size of the image. If it failed
    // to load, either of these should be zero.
    if (img.naturalWidth === 0) {
        return false;
    }

    // No other way of checking: assume it’s ok.
    return true;
}
SLaks
la source
1
Intéressant, je regardais ce post plus tôt et je ne savais pas qu'ils faisaient! complet pour IE car naturalWidth n'est pas défini dans IE. Je vais le vérifier maintenant.
William
3
Apparemment, cela ne fonctionne de manière fiable que la première fois. Si vous modifiez ensuite le src de l'image, au moins safari mobile continuera de signaler la première valeur pour naturalWidth et complete.
giorgian
5
return img.complete && typeof img.naturalWidth! = 'undefined' && img.naturalWidth! = 0;
Adrian Seeley
5
@vsync, vous voudrez probablement l'utiliser comme une vérification unique, et si l'image n'a pas encore été chargée, configurez un gestionnaire d'événements "load". Il ne devrait pas être nécessaire de marteler le processeur en exécutant cette vérification plusieurs fois.
Michael Martin-Smucker
2
Pour les curieux, c'est à peu près exactement ce que fait la bibliothèque imagesLoaded liée ci-dessous. Donc, pour une utilisation unique, allez-y: github.com/desandro/imagesloaded/blob/master/…
cincodenada
57

Sur la base de ma compréhension de la spécification HTML W3C pour l' imgélément , vous devriez pouvoir le faire en utilisant une combinaison des attributs completeet naturalHeight, comme ceci:

function imgLoaded(imgElement) {
  return imgElement.complete && imgElement.naturalHeight !== 0;
}

De la spécification de l' completeattribut:

L'attribut IDL complete doit renvoyer true si l'une des conditions suivantes est vraie:

  • L'attribut src est omis.
  • La tâche finale mise en file d'attente par la source de tâches de mise en réseau une fois la ressource récupérée a été mise en file d'attente.
  • L'élément img est entièrement disponible.
  • L'élément img est cassé.

Sinon, l'attribut doit retourner false.

Donc, essentiellement, completerenvoie true si l'image a terminé le chargement ou n'a pas pu se charger. Puisque nous voulons uniquement le cas où l'image a été chargée avec succès, nous devons également vérifier l' nauturalHeightattribut:

L'IDL attribue naturalWidthet naturalHeightdoit renvoyer la largeur et la hauteur intrinsèques de l'image, en pixels CSS, si l'image est disponible, sinon 0.

Et availableest défini comme suit:

Un img est toujours dans l'un des états suivants:

  • Non disponible - L'agent utilisateur n'a obtenu aucune donnée d'image.
  • Partiellement disponible - L'agent utilisateur a obtenu certaines des données d'image.
  • Entièrement disponible - L'agent utilisateur a obtenu toutes les données d'image et au moins les dimensions de l'image sont disponibles.
  • Cassé - L'agent utilisateur a obtenu toutes les données d'image qu'il peut, mais il ne peut même pas décoder suffisamment l'image pour obtenir les dimensions de l'image (par exemple, l'image est corrompue, ou le format n'est pas pris en charge, ou aucune donnée n'a pu être obtenue) .

Lorsqu'un élément img est soit dans l'état partiellement disponible soit dans l'état complètement disponible, il est dit qu'il est disponible.

Donc, si l'image est "cassée" (échec du chargement), alors elle sera à l'état cassé, pas à l'état disponible, donc naturalHeight sera donc à 0.

Par conséquent, la vérification imgElement.complete && imgElement.naturalHeight !== 0 doit nous indiquer si l'image a été chargée avec succès.

Vous pouvez en savoir plus à ce sujet dans la spécification HTML W3C pour l' imgélément , ou sur MDN .

Ajedi32
la source
1
Ne fonctionne pas, l'image est chargée avec le style "content: url"
deathangel908
1
Cela ne semble pas fonctionner dans Firefox avec des images SVG car le navigateur rapporte une hauteur / largeur naturelle égale à 0. Bogue
leeb
20

J'ai essayé de nombreuses façons différentes et c'est la seule qui a fonctionné pour moi

//check all images on the page
$('img').each(function(){
    var img = new Image();
    img.onload = function() {
        console.log($(this).attr('src') + ' - done!');
    }
    img.src = $(this).attr('src');
});

Vous pouvez également ajouter une fonction de rappel déclenchée une fois que toutes les images sont chargées dans le DOM et prêtes. Cela s'applique également aux images ajoutées dynamiquement. http://jsfiddle.net/kalmarsh80/nrAPk/

Kal
la source
Lien jsfiddle rompu
Alex Karshin
1
J'ai testé les lectures intéressantes ci-dessus et elles échouent entre les tests mis en cache / non mis en cache sur une poignée de navigateurs courants. Cette réponse est similaire à une autre, mais c'est celle que j'ai implémentée et testée tout à l'heure, je peux confirmer qu'elle fonctionne sur: EdgeWin10, IE11Win8.1, Win7IE10, Win7IE9, iOS 10.2 Chrome, iOS 10.2 Safari, mac os 10.12 Chrome, mac os 10.12 Safari, mac os 10.12 Firefox, Google Pixel 7.1, Samsung S5 Android 4.4. N'oubliez pas d'utiliser addEventListener / removeEventListener aussi: D
danjah
13

Utiliser la imagesLoadedbibliothèque javascript .

Utilisable avec du Javascript simple et en tant que plugin jQuery.

Fonctionnalités:

Ressources

Josh Harrison
la source
Cela a parfaitement fonctionné pour moi. function checkImages (imgs) {$ (imgs) .each (function () {$ (imgs) .imagesLoaded () .progress (fonction (instance, image) {if (image.isLoaded == false) {console.log (image) .img.src + 'est introuvable.'); image.img.src = "/templates/img/no-image.jpg";}});}); }
Rooster242
1
il semble avoir des tonnes de problèmes ouverts qui causent des bugs majeurs, et le développeur ne semble pas faire grand-chose pour les rattraper. pour l'instant, cela est totalement inutilisable dans un environnement de production.
vsync
3
@vsync Avez-vous lu certains des problèmes en suspens? Il répond à presque tous, et la plupart semblent être des cas marginaux non reproductibles que peu d'autres rencontrent. Je n'ai jamais eu de problème avec ça en production.
Josh Harrison
1
oui je l'utilise moi-même et parfois cela ne fonctionne pas, donc j'utilise un setTimeout pour couvrir les cas où il échoue
vsync
Il y a de bonnes raisons POURQUOI on veut utiliser le plugin imagesLoaded: la completepropriété ne semble pas être clairement supportée: impossible de trouver une source fiable d'informations concernant le support du navigateur. completeLa propriété ne semble pas non plus avoir de spécification claire: la spécification HTML5 est la seule à le mentionner et elle est toujours dans une version préliminaire au moment de l'écriture. Si vous utilisez naturalWidthet naturalHeightne supportez que IE9 +, donc si vous l'utilisez pour savoir si l'image est chargée, vous avez besoin d'une astuce "intelligente" pour la faire fonctionner sur les anciens navigateurs, et vous devez vérifier que le comportement entre les navigateurs est cohérent
Adrien Soyez
8

Récupérez les informations des éléments de l'image sur la page
Test de travail sur Chrome et Firefox
Travail jsFiddle (ouvrez votre console pour voir le résultat)

$('img').each(function(){ // selecting all image element on the page

    var img = new Image($(this)); // creating image element

    img.onload = function() { // trigger if the image was loaded
        console.log($(this).attr('src') + ' - done!');
    }

    img.onerror = function() { // trigger if the image wasn't loaded
        console.log($(this).attr('src') + ' - error!');
    }

    img.onAbort = function() { // trigger if the image load was abort
        console.log($(this).attr('src') + ' - abort!');
    }

    img.src = $(this).attr('src'); // pass src to image object

    // log image attributes
    console.log(img.src);
    console.log(img.width);
    console.log(img.height);
    console.log(img.complete);

});

Remarque: j'ai utilisé jQuery , je pensais que cela pouvait être obtenu en javascript complet

Je trouve de bonnes informations ici OpenClassRoom -> c'est un forum français

Julha
la source
3

Détecteur de réseau en temps réel - vérifiez l'état du réseau sans rafraîchir la page: (ce n'est pas jquery, mais testé, et fonctionne à 100%: (testé sur Firefox v25.0))

Code:

<script>
 function ImgLoad(myobj){
   var randomNum = Math.round(Math.random() * 10000);
   var oImg=new Image;
   oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
   oImg.onload=function(){alert('Image succesfully loaded!')}
   oImg.onerror=function(){alert('No network connection or image is not available.')}
}
window.onload=ImgLoad();
</script>

<button id="reloadbtn" onclick="ImgLoad();">Again!</button>

si la connexion est perdue, appuyez simplement sur le bouton Again.

Mise à jour 1: détection automatique sans rafraîchissement de la page:

<script>
     function ImgLoad(myobj){
       var randomNum = Math.round(Math.random() * 10000);
       var oImg=new Image;
       oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
       oImg.onload=function(){networkstatus_div.innerHTML="";}
       oImg.onerror=function(){networkstatus_div.innerHTML="Service is not available. Please check your Internet connection!";}
}

networkchecker = window.setInterval(function(){window.onload=ImgLoad()},1000);
</script>

<div id="networkstatus_div"></div>
Jenei Tamás
la source
100%! Que faire si votre lien d'image est bloqué par un proxy / pare-feu ou si le serveur d'images ne répond pas? Vous avez toujours le réseau qui fonctionne :)
Sen Jacob
Cela chargera à nouveau chaque image à partir du serveur, brisant le cache (intentionnellement). Donc, juste pour vérifier, vous doublez (au moins) la bande passante pour toutes vos images. En outre, il vérifie uniquement si l'image existe sur le serveur, et non si elle a été chargée à un endroit spécifique. Aussi aucun moyen de savoir quand chaque image est chargée.
Marius Balčytis
3

Après avoir lu les solutions intéressantes sur cette page, j'ai créé une solution facile à utiliser très influencée par la publication de SLaks et Noyo qui semble fonctionner sur des versions assez récentes (au moment de l'écriture) de Chrome, IE, Firefox, Safari et Opera (tout sous Windows). En outre, cela a fonctionné sur un émulateur iPhone / iPad que j'ai utilisé.

Une différence majeure entre cette solution et la publication de SLaks et Noyo est que cette solution vérifie principalement les propriétés naturalWidth et naturalHeight. J'ai trouvé que dans les versions actuelles du navigateur, ces deux propriétés semblent fournir les résultats les plus utiles et les plus cohérents.

Ce code renvoie VRAI lorsqu'une image a été entièrement chargée ET avec succès. Il renvoie FAUX lorsqu'une image n'a pas encore été entièrement chargée OU n'a pas pu se charger.

Une chose que vous devez savoir est que cette fonction retournera également FALSE si l'image est une image de 0x0 pixel. Mais ces images sont assez rares, et je ne peux pas penser à un cas très utile où vous voudriez vérifier si une image 0x0 pixel a encore été chargée :)

Nous attachons d'abord une nouvelle fonction appelée "isLoaded" au prototype HTMLImageElement, afin que la fonction puisse être utilisée sur n'importe quel élément d'image.

HTMLImageElement.prototype.isLoaded = function() {

    // See if "naturalWidth" and "naturalHeight" properties are available.
    if (typeof this.naturalWidth == 'number' && typeof this.naturalHeight == 'number')
        return !(this.naturalWidth == 0 && this.naturalHeight == 0);

    // See if "complete" property is available.
    else if (typeof this.complete == 'boolean')
        return this.complete;

    // Fallback behavior: return TRUE.
    else
        return true;

};

Ensuite, chaque fois que nous devons vérifier l'état de chargement de l'image, nous appelons simplement la fonction "isLoaded".

if (someImgElement.isLoaded()) {
    // YAY! The image loaded
}
else {
    // Image has not loaded yet
}

Selon le commentaire de Giorgian sur la publication de SLaks et Noyo, cette solution ne peut probablement être utilisée comme vérification unique sur Safari Mobile que si vous prévoyez de changer l'attribut SRC. Mais vous pouvez contourner cela en créant un élément d'image avec un nouvel attribut SRC au lieu de modifier l'attribut SRC sur un élément d'image existant.

data-dan
la source
2

Voici comment je l'ai fait fonctionner avec plusieurs navigateurs en utilisant une combinaison des méthodes ci-dessus (j'avais également besoin d'insérer des images dynamiquement dans le dom):

$('#domTarget').html('<img src="" />');

var url = '/some/image/path.png';

$('#domTarget img').load(function(){}).attr('src', url).error(function() {
    if ( isIE ) {
       var thisImg = this;
       setTimeout(function() {
          if ( ! thisImg.complete ) {
             $(thisImg).attr('src', '/web/css/img/picture-broken-url.png');
          }
       },250);
    } else {
       $(this).attr('src', '/web/css/img/picture-broken-url.png');
    }
});

Remarque: Vous devrez fournir un état booléen valide pour la variable isIE.

Justin Vincent
la source
2
var isImgLoaded = function(imgSelector){
  return $(imgSelector).prop("complete") && $(imgSelector).prop("naturalWidth") !== 0;
}

// Ou en tant que plugin

    $.fn.extend({
      isLoaded: function(){
        return this.prop("complete") && this.prop("naturalWidth") !== 0;
      }
    })

// $(".myImage").isLoaded() 
KhaledDev
la source
1

Si je comprends bien, la propriété .complete n'est pas standard. Ce n'est peut-être pas universel ... Je remarque qu'il semble fonctionner différemment dans Firefox vers IE. Je charge un certain nombre d'images en javascript puis vérifie si elles sont terminées. Dans Firefox, cela semble très bien fonctionner. Dans IE, ce n'est pas le cas car les images semblent se charger sur un autre thread. Cela ne fonctionne que si je mets un délai entre mon affectation à image.src et lorsque je vérifie la propriété image.complete.

L'utilisation de image.onload et image.onerror ne fonctionne pas non plus pour moi, car je dois passer un paramètre pour savoir de quelle image je parle lorsque la fonction est appelée. Toute façon de faire cela semble échouer car elle semble en fait passer la même fonction, pas différentes instances de la même fonction. Donc la valeur que je lui passe pour identifier l'image finit toujours par être la dernière valeur de la boucle. Je ne peux penser à aucun moyen de contourner ce problème.

Sur Safari et Chrome, je vois l'image.complete vraie et la largeur naturelle définie même lorsque la console d'erreur affiche un 404 pour cette image ... et j'ai intentionnellement supprimé cette image pour tester cela. Mais ce qui précède fonctionne bien pour Firefox et IE.

user1018645
la source
Hmm, c'est intéressant. Cela vous dérangerait-il de publier un exemple de code, donc je veux essayer quelques choses?
Xavi
1

Cet extrait de code m'a aidé à résoudre les problèmes de mise en cache du navigateur:

$("#my_image").on('load', function() {

    console.log("image loaded correctly"); 
}).each(function() {

     if($(this).prop('complete')) $(this).load();
});

Lorsque le cache du navigateur est désactivé, seul ce code ne fonctionne pas:

$("#my_image").on('load', function() {
     console.log("image loaded correctly"); 
})

pour le faire fonctionner, vous devez ajouter:

.each(function() {
     if($(this).prop('complete')) $(this).load();
});
Franc
la source
0

En utilisant ce JavaScriptcode, vous pouvez vérifier que l'image est correctement chargée ou non.

document.onready = function(e) {
        var imageobj = new Image();
        imageobj.src = document.getElementById('img-id').src;
        if(!imageobj.complete){ 
            alert(imageobj.src+"  -  Not Found");
        }
}

Essayez ceci

Ajay Gupta
la source
0

J'ai eu beaucoup de problèmes avec la charge complète d'une image et l'EventListener.

Quoi que j'aie essayé, les résultats n'étaient pas fiables.

Mais j'ai trouvé la solution. Ce n'est techniquement pas agréable, mais maintenant je n'ai jamais eu de chargement d'image défaillant.

Ce que j'ai fait:

                    document.getElementById(currentImgID).addEventListener("load", loadListener1);
                    document.getElementById(currentImgID).addEventListener("load", loadListener2);

                function loadListener1()
                    {
                    // Load again
                    }

                function loadListener2()
                {
                    var btn = document.getElementById("addForm_WithImage"); btn.disabled = false;
                    alert("Image loaded");
                }

Au lieu de charger l'image une fois, je la charge juste une deuxième fois directement après la première fois et les deux s'exécutent via le gestionnaire d'événements.

Tous mes maux de tête ont disparu!


Au fait: les gars de stackoverflow m'ont déjà aidé plus de cent fois. Pour cela un très grand merci!

Scoobeedo Cool
la source
0

Celui-ci a bien fonctionné pour moi :)

$('.progress-image').each(function(){
    var img = new Image();
    img.onload = function() {
        let imgSrc = $(this).attr('src');
        $('.progress-image').each(function(){
            if($(this).attr('src') == imgSrc){
                console.log($(this).parent().closest('.real-pack').parent().find('.shimmer').fadeOut())
            }
        })
    }
    img.src = $(this).attr('src');
});
Kannan Uthaman
la source