Como criar um retorno de chamada JavaScript para saber quando uma imagem é carregada?

136

Quero saber quando uma imagem terminou de carregar. Existe uma maneira de fazer isso com um retorno de chamada?

Caso contrário, existe alguma maneira de fazer isso?

Ciro Santilli adicionou uma nova foto
fonte
2
github.com/desandro/imagesloaded - Pessoal, verifique este pacote.
Mangatinanda

Respostas:

159

.complete + retorno de chamada

Este é um método compatível com os padrões, sem dependências extras e não espera mais que o necessário:

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/

Ciro Santilli adicionou uma nova foto
fonte
4
Isso pode dar errado se a imagem for concluída entre a img.completeligação e a addEventListenerligação?
Thomas Ahle
@ThomasAhle Não sou especialista, mas isso parece possível. Vamos ver se alguém tem uma solução.
Ciro Santilli # 10/17
Eu acho que seria apenas uma questão de código paralelo, que a maioria javascript provavelmente não é ..
Thomas Ahle
4
@ThomasAhle Não pode, porque o navegador só dispara o evento load quando a fila de eventos é girada. Dito isso, o loadouvinte de evento deve estar em uma elsecláusula, como img.completepode se tornar realidade antes do loadevento ser disparado, portanto, se não fosse, você poderia ter loadedchamado duas vezes (observe que é relativamente provável que isso mude, de forma que img.completesó se torna verdadeira quando o evento incêndios).
gsnedders
72

Image.onload () geralmente funciona.

Para usá-lo, será necessário vincular o manipulador de eventos antes de definir o atributo src.

Links Relacionados:

Exemplo de uso:

    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
fonte
26
FYI: De acordo com as especificações do W3C, onload não é um evento válido para elementos IMG. Obviamente, os navegadores suportam, mas se você se preocupa com as especificações e não tem 100% de certeza de que todos os navegadores que você deseja direcionar suportam isso, convém repensá-lo ou, pelo menos, ter isso em mente.
Jason Bunting
3
por que esperar 5 segundos para definir a fonte parece uma má idéia?
quemeful
8
@ Quemeful é por isso que é chamado "um exemplo".
Diego Jancic
3
@JasonBunting O que você está vendo que faz você pensar que o loadevento não é válido? html.spec.whatwg.org/multipage/webappapis.html#handler-onload é a definição do onload manipulador de eventos.
precisa saber é o seguinte
4
@gsnedders - você percebe, eu presumo, que quando escrevi esse comentário, estava me referindo ao padrão existente, não àquele que você apontou, que é 4,5 anos mais novo. Se você tivesse perguntado naquela época, eu poderia ter apontado para isso, talvez. Essa é a natureza da web, certo? As coisas ficam velho ou são movidas ou são modificados, etc.
Jason Bunting
20

Você pode usar a propriedade .complete da classe de imagem Javascript.

Eu tenho um aplicativo no qual armazeno vários objetos de imagem em uma matriz, que serão adicionados dinamicamente à tela e, enquanto eles carregam, escrevo atualizações para outra div na página. Aqui está um trecho de código:

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
fonte
Eu usei código semelhante no meu trabalho antes. Isso funciona bem em todos os navegadores.
Gabriel Hurley
2
O problema com a verificação concluída é que, a partir do IE9, os eventos OnLoad são disparados antes que todas as imagens sejam carregadas e é difícil encontrar um gatilho para a função de verificação agora.
Gene Vincent
8

A vida é muito curta para o 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
fonte
1
Essa é uma ótima resposta, mas acho que você nem precisa de muito código. Você está apenas fazendo com que pareça confuso adicionando o srcJS.
precisa
1
O tempo é uma grande restrição na programação. Pela minha experiência, escrever código legível (por algum tempo) oferece um enorme benefício de tempo.
Idan Beker
Por que você armazenaria o src em uma nova variável apenas para consumi-lo na próxima linha? Se a brevidade é seu objetivo, é um antipadrão. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620faz o truque.
Josias
3

Aqui está o equivalente jQuery:

var $img = $('img');

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

function triggerAction() {
   alert('img has been loaded');
}
Alexander Drobyshevsky
fonte
1

Não é adequado para 2008 quando a pergunta foi feita, mas hoje em dia isso funciona bem para mim:

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

essas funções resolverão o problema, você precisará implementar a DrawThumbnailsfunção e ter uma variável global para armazenar as imagens. Adoro fazer isso funcionar com um objeto de classe que possui a ThumbnailImageArrayvariável como membro, mas estou com dificuldades!

chamado como em 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
fonte
11
A maior parte desse código é irrelevante, incluindo toda a sua addThumbnailImagesfunção. Analise o código relevante e removerei o -1.
23812 Justin Morgan
0

Se o objetivo é estilizar o img depois que o navegador renderizar a imagem, você deverá:

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

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

porque o navegador primeiro loads the compressed version of image, depois decodes it, finalmente paints. como não há evento, paintvocê deve executar sua lógica após o navegador ter decodeda tag img.

Sajad
fonte
-2

Se você estiver usando o React.js, poderá fazer o seguinte:

render() {

// ...

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

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

// ...}

Onde:

  • - onLoad (...) agora será chamado com algo assim: {src: " https: //......png ", key: "1"}, você pode usar isso como "key" para saber quais imagens está carregado corretamente e quais não.
  • - onError (...) é o mesmo, exceto por erros.
  • - o objeto "item" é algo como este {key: "..", src: ".."} que você pode usar para armazenar o URL e a chave das imagens, para usar em uma lista de imagens.

  • Mike
    fonte