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


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/


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>


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

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="">


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

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

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

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.


-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.

  • Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
    Licensed under cc by-sa 3.0 with attribution required.