Comment créer un rappel JavaScript pour savoir quand une image est chargée?

Réponses:

159

.complete + rappel

Il s'agit d'une méthode conforme aux normes sans dépendances supplémentaires et n'attend pas plus longtemps que nécessaire:

var img = document.querySelector('img')

function loaded() {
  alert('loaded')
}

if (img.complete) {
  loaded()
} else {
  img.addEventListener('load', loaded)
  img.addEventListener('error', function() {
      alert('error')
  })
}

Source: http://www.html5rocks.com/en/tutorials/es6/promises/

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
4
Cela peut-il mal tourner si l'image se termine entre l' img.completeappel et l' addEventListenerappel?
Thomas Ahle
@ThomasAhle Je ne suis pas un expert, mais cela semble possible. Voyons si quelqu'un a une solution.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Je suppose que ce ne serait un problème que pour le code parallèle, ce que la plupart des javascript ne sont probablement pas ..
Thomas Ahle
4
@ThomasAhle Cela ne peut pas, car le navigateur ne déclenchera l'événement de chargement que lorsque la file d'attente d'événements est lancée. Cela dit, l' loadécouteur d'événements doit être dans une elseclause, comme cela img.completepeut devenir vrai avant que l' loadévénement ne soit déclenché, donc si ce n'était pas le cas, vous auriez pu potentiellement loadedappeler deux fois (notez que cela est relativement susceptible de changer de sorte que cela img.completene devient vrai que lorsque l'événement les feux).
gsnedders
72

Image.onload () fonctionnera souvent.

Pour l'utiliser, vous devez vous assurer de lier le gestionnaire d'événements avant de définir l'attribut src.

Liens connexes:

Exemple d'utilisation:

    window.onload = function () {

        var logo = document.getElementById('sologo');

        logo.onload = function () {
            alert ("The image has loaded!");		
        };

        setTimeout(function(){
            logo.src = 'https://edmullen.net/test/rc.jpg';         
        }, 5000);
    };
 <html>
    <head>
    <title>Image onload()</title>
    </head>
    <body>

    <img src="#" alt="This image is going to load" id="sologo"/>

    <script type="text/javascript">

    </script>
    </body>
    </html>

Keparo
la source
26
FYI: Selon les spécifications du W3C, onload n'est pas un événement valide pour les éléments IMG. De toute évidence, les navigateurs le prennent en charge, mais si vous vous souciez de la spécification et n'êtes pas sûr à 100% que tous les navigateurs que vous souhaitez cibler le prennent en charge, vous voudrez peut-être le repenser ou du moins le garder à l'esprit.
Jason Bunting
3
Pourquoi attendre 5 secondes pour définir la source semble-t-il une mauvaise idée?
quemeful
8
@quemeful c'est pourquoi on l'appelle "un exemple".
Diego Jancic
3
@JasonBunting Qu'est-ce que vous regardez qui vous fait penser que l' loadévénement n'est pas valide? html.spec.whatwg.org/multipage/webappapis.html#handler-onload est la définition du onload gestionnaire d'événements.
gsnedders
4
@gsnedders - vous réalisez, je suppose, que lorsque j'ai écrit ce commentaire, je faisais référence à la norme existante, pas à celle que vous avez mentionnée, qui est plus récente de 4,5 ans. Si vous aviez demandé à l'époque, j'aurais peut-être pu le signaler. Telle est la nature du Web, non? Les choses vieillissent ou sont déplacées ou modifiées, etc.
Jason Bunting
20

Vous pouvez utiliser la propriété .complete de la classe d'image Javascript.

J'ai une application où je stocke un certain nombre d'objets Image dans un tableau, qui seront ajoutés dynamiquement à l'écran, et au fur et à mesure qu'ils se chargent, j'écris des mises à jour sur un autre div sur la page. Voici un extrait de code:

var gAllImages = [];

function makeThumbDivs(thumbnailsBegin, thumbnailsEnd)
{
    gAllImages = [];

    for (var i = thumbnailsBegin; i < thumbnailsEnd; i++) 
    {
        var theImage = new Image();
        theImage.src = "thumbs/" + getFilename(globals.gAllPageGUIDs[i]);
        gAllImages.push(theImage);

        setTimeout('checkForAllImagesLoaded()', 5);
        window.status="Creating thumbnail "+(i+1)+" of " + thumbnailsEnd;

        // make a new div containing that image
        makeASingleThumbDiv(globals.gAllPageGUIDs[i]);
    }
}

function checkForAllImagesLoaded()
{
    for (var i = 0; i < gAllImages.length; i++) {
        if (!gAllImages[i].complete) {
            var percentage = i * 100.0 / (gAllImages.length);
            percentage = percentage.toFixed(0).toString() + ' %';

            userMessagesController.setMessage("loading... " + percentage);
            setTimeout('checkForAllImagesLoaded()', 20);
            return;
        }
    }

    userMessagesController.setMessage(globals.defaultTitle);
}
Jon DellOro
la source
J'ai déjà utilisé un code similaire dans mon travail. Cela fonctionne bien dans tous les navigateurs.
Gabriel Hurley
2
Le problème avec la vérification terminée est qu'à partir d'IE9, les événements OnLoad sont déclenchés avant que toutes les images ne soient chargées et qu'il est difficile de trouver un déclencheur pour la fonction de vérification maintenant.
Gene Vincent
8

La vie est trop courte pour jquery.

function waitForImageToLoad(imageElement){
  return new Promise(resolve=>{imageElement.onload = resolve})
}

var myImage = document.getElementById('myImage');
var newImageSrc = "https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620"

myImage.src = newImageSrc;
waitForImageToLoad(myImage).then(()=>{
  // Image have loaded.
  console.log('Loaded lol')
});
<img id="myImage" src="">

Idan Beker
la source
1
C'est une excellente réponse, mais je ne pense pas que vous ayez même besoin de beaucoup de code. Vous donnez juste un air déroutant en ajoutant le srcavec JS.
Brandon Benefield
1
Le temps est une énorme contrainte dans la programmation. D'après mon expérience, l'écriture de code lisible (bien que longtemps) donne un énorme gain de temps.
Idan Beker
Pourquoi stockeriez-vous le src dans une nouvelle variable uniquement pour le consommer sur la ligne suivante? Si la brièveté est votre objectif, c'est un anti-modèle. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620fait l'affaire.
Josiah
3

Voici l'équivalent de jQuery:

var $img = $('img');

if ($img.length > 0 && !$img.get(0).complete) {
   $img.on('load', triggerAction);
}

function triggerAction() {
   alert('img has been loaded');
}
Alexandre Drobyshevsky
la source
1

Ne convient pas pour 2008 lorsque la question a été posée, mais ces jours-ci, cela fonctionne bien pour moi:

async function newImageSrc(src) {
  // Get a reference to the image in whatever way suits.
  let image = document.getElementById('image-id');

  // Update the source.
  img.src = src;

  // Wait for it to load.
  await new Promise((resolve) => { image.onload = resolve; });

  // Done!
  console.log('image loaded! do something...');
}
Hugh
la source
0

ces fonctions résoudront le problème, vous devez implémenter la DrawThumbnailsfonction et avoir une variable globale pour stocker les images. J'adore faire fonctionner cela avec un objet de classe qui a ThumbnailImageArraycomme variable membre, mais j'ai du mal!

appelé comme dans addThumbnailImages(10);

var ThumbnailImageArray = [];

function addThumbnailImages(MaxNumberOfImages)
{
    var imgs = [];

    for (var i=1; i<MaxNumberOfImages; i++)
    {
        imgs.push(i+".jpeg");
    }

    preloadimages(imgs).done(function (images){
            var c=0;

            for(var i=0; i<images.length; i++)
            {
                if(images[i].width >0) 
                {
                    if(c != i)
                        images[c] = images[i];
                    c++;
                }
            }

            images.length = c;

            DrawThumbnails();
        });
}



function preloadimages(arr)
{
    var loadedimages=0
    var postaction=function(){}
    var arr=(typeof arr!="object")? [arr] : arr

    function imageloadpost()
    {
        loadedimages++;
        if (loadedimages==arr.length)
        {
            postaction(ThumbnailImageArray); //call postaction and pass in newimages array as parameter
        }
    };

    for (var i=0; i<arr.length; i++)
    {
        ThumbnailImageArray[i]=new Image();
        ThumbnailImageArray[i].src=arr[i];
        ThumbnailImageArray[i].onload=function(){ imageloadpost();};
        ThumbnailImageArray[i].onerror=function(){ imageloadpost();};
    }
    //return blank object with done() method    
    //remember user defined callback functions to be called when images load
    return  { done:function(f){ postaction=f || postaction } };
}
Dave
la source
11
La plupart de ce code n'est pas pertinent, y compris l'ensemble de votre addThumbnailImagesfonction. Réduisez-le au code pertinent et je supprimerai le -1.
Justin Morgan
0

Si l'objectif est de styliser l'image une fois que le navigateur a rendu l'image, vous devez:

const img = new Image();
img.src = 'path/to/img.jpg';

img.decode().then(() => {
/* set styles */
/* add img to DOM */ 
});

parce que le navigateur d'abord loads the compressed version of image, puis decodes it, enfin paints. car il n'y a pas d'événement pour paintvous devez exécuter votre logique après que le navigateur ait decodedla balise img.

Sajad
la source
-2

Si vous utilisez React.js, vous pouvez le faire:

render() {

// ...

<img 
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}

src={item.src} key={item.key}
ref={item.key} />

// ...}

Où:

  • - onLoad (...) sera maintenant appelé avec quelque chose comme ceci: {src: " https: //......png ", key: "1"} vous pouvez utiliser ceci comme "clé" pour savoir quelles images est chargé correctement et qui non.
  • - onError (...) c'est pareil mais pour les erreurs.
  • - l'objet "item" est quelque chose comme ceci {key: "..", src: ".."} que vous pouvez utiliser pour stocker l'URL et la clé des images afin de les utiliser dans une liste d'images.

  • Mike
    la source