Come creare un callback JavaScript per sapere quando viene caricata un'immagine?


Risposte:


159

.complete + callback

Questo è un metodo conforme agli standard senza dipendenze extra e non attende più del necessario:

var img = document.querySelector('img')

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

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

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


4
Questo può andare storto se l'immagine viene completata tra la img.completechiamata e la addEventListenerchiamata?
Thomas Ahle,

@ThomasAhle Non sono un esperto, ma sembra possibile. Vediamo se qualcuno ha una soluzione.
Ciro Santilli 10 冠状 病 六四 事件 法轮功

Immagino che sarebbe solo un problema per il codice parallelo, che la maggior parte di javascript probabilmente non è ..
Thomas Ahle

4
@ThomasAhle Non può, perché il browser attiverà l'evento load solo quando viene fatta girare la coda degli eventi. Detto questo, il loadlistener di eventi deve essere in una elseclausola, poiché img.completepuò diventare vero prima che l' loadevento venga generato, quindi se non lo fosse potevi potenzialmente loadedchiamare due volte (nota che è relativamente probabile che cambi in modo tale che img.completediventa vero solo quando l'evento incendi).
gsnedders

72

Image.onload () funzionerà spesso.

Per usarlo, devi essere sicuro di associare il gestore eventi prima di impostare l'attributo src.

Link correlati:

Esempio di utilizzo:

    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>


26
Cordiali saluti: Secondo le specifiche del W3C, l'onload non è un evento valido per gli elementi IMG. Ovviamente i browser lo supportano, ma se ti preoccupi delle specifiche e non sei sicuro al 100% che tutti i browser a cui vuoi indirizzare supportino questo, potresti voler ripensarlo o almeno tenerlo a mente.
Jason Bunting,

3
perché aspettare 5 secondi per impostare la sorgente sembra una cattiva idea?
quemeful

8
@quemeful ecco perché si chiama "un esempio".
Diego Jancic,

3
@JasonBunting Cosa stai guardando che ti fa pensare che l' loadevento non sia valido? html.spec.whatwg.org/multipage/webappapis.html#handler-onload è la definizione del onload gestore eventi.
gsnedders

4
@gsnedders - ti rendi conto, presumo, che quando ho scritto quel commento, mi riferivo allo standard esistente, non a quello che hai indicato, che è 4,5 anni più recente. Se l'avessi chiesto allora, avrei potuto indicarlo, forse. Tale è la natura del web, giusto? Le cose invecchiano o vengono spostate o modificate, ecc.
Jason Bunting,

20

È possibile utilizzare la proprietà .complete della classe di immagini Javascript.

Ho un'applicazione in cui memorizzo un numero di oggetti Image in un array, che verranno aggiunti dinamicamente allo schermo e mentre caricano scrivo aggiornamenti su un altro div sulla pagina. Ecco uno snippet di codice:

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);
}

Ho usato codice simile nel mio lavoro prima. Funziona bene in tutti i browser.
Gabriel Hurley,

2
Il problema con il controllo completo è che a partire da IE9 gli eventi OnLoad vengono generati prima che tutte le immagini vengano caricate ed è difficile trovare un trigger per la funzione di controllo ora.
Gene Vincent,


8

La vita è troppo breve per 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="">


1
Questa è un'ottima risposta, ma non credo che tu abbia nemmeno bisogno di tanto codice. Stai solo facendo sembrare confuso aggiungendo il srccon JS.
Brandon Benefield

1
Il tempo è un enorme limite nella programmazione. Dalla mia esperienza, scrivere un codice leggibile (anche se per un po 'di tempo) offre un enorme vantaggio in termini di tempo.
Idan Beker

Perché dovresti memorizzare l'src in una nuova variabile solo per consumarlo nella riga successiva? Se la brevità è il tuo obiettivo, questo è un anti-schema. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620fa il trucco.
Giosia

3

Ecco l'equivalente di jQuery:

var $img = $('img');

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

function triggerAction() {
   alert('img has been loaded');
}

1

Non adatto per il 2008 quando è stata posta la domanda, ma in questi giorni funziona bene per me:

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...');
}

0

queste funzioni risolveranno il problema, è necessario implementare la DrawThumbnailsfunzione e disporre di una variabile globale per memorizzare le immagini. Adoro farlo funzionare con un oggetto di classe che ha ThumbnailImageArraycome variabile membro, ma sto lottando!

chiamato come in 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 } };
}

11
La maggior parte di questo codice è irrilevante, inclusa l'intera addThumbnailImagesfunzione. Analizzalo fino al codice pertinente e rimuoverò -1.
Justin Morgan,

0

Se l'obiettivo è lo stile di img dopo che il browser ha reso l'immagine, dovresti:

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

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

perché prima il browser loads the compressed version of image, poi decodes itfinalmente paints. poiché non esiste alcun evento per paintte, dovresti eseguire la tua logica dopo che il browser ha decodedil tag img.


-2

Se stai usando React.js, puoi farlo:

render() {

// ...

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

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

// ...}

Dove:

  • - onLoad (...) ora chiamerà con qualcosa del genere: {src: " https: //......png ", chiave: "1"} puoi usarlo come "chiave" per sapere quali immagini è caricato correttamente e quale no.
  • - onError (...) è lo stesso ma per errori.
  • - l'oggetto "item" è qualcosa del genere {key: "..", src: ".."} che puoi usare per memorizzare l'URL e la chiave delle immagini da utilizzare in un elenco di immagini.

  • Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
    Licensed under cc by-sa 3.0 with attribution required.