Verifique se uma imagem está carregada (sem erros) com jQuery

224

Estou usando JavaScript com a biblioteca jQuery para manipular as miniaturas de imagens contidas em uma lista não ordenada. Quando a imagem é carregada, ela faz uma coisa; quando ocorre um erro, ela faz outra coisa. Estou usando jQuery load()e error()métodos como eventos. Após esses eventos, verifico o elemento DOM da imagem para o arquivo .complete para garantir que a imagem já não esteja carregada antes que o jQuery possa registrar os eventos.

Funciona corretamente, exceto quando ocorre um erro antes que o jQuery possa registrar os eventos. A única solução em que consigo pensar é usar o onerroratributo img para armazenar uma "flag" em algum lugar globalmente (ou no próprio nó) que diz que falhou, para que o jQuery possa verificar essa "store / node" ao verificar .complete.

Alguém tem uma solução melhor?

Editar: pontos principais em negrito e detalhes adicionais adicionados abaixo: Estou verificando se uma imagem está completa (também carregada) DEPOIS de adicionar um evento de carga e erro à imagem. Dessa forma, se a imagem foi carregada antes dos eventos serem registrados, eu ainda saberei. Se a imagem não for carregada após os eventos, os eventos cuidarão dela quando o fizer. O problema é que posso verificar facilmente se uma imagem já está carregada, mas não sei se ocorreu um erro.

William
fonte
Quando você registra os eventos do jQuery? Talvez alguns códigos ajudem. :)
okw 30/12/2009
Há muito código, o que eu disse acima é apenas uma versão muito simples do que estou fazendo. Eu chamo os eventos depois que o DOM é carregado, um método é chamado para adicionar eventos às miniaturas.
William

Respostas:

250

Outra opção é acionar os eventos onloade / ou onerrorcriando um elemento de imagem na memória e configurando seu srcatributo para o srcatributo original da imagem original. Aqui está um exemplo do que quero dizer:

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

Espero que isto ajude!

Xavi
fonte
27
Não parece estar funcionando tão bem quanto eu esperava. No Google Chrome, parece haver problemas quando a imagem já está em cache. Não aciona o método load (). :(
William
4
Ugg, você está certo. O Chrome é definitivamente o navegador mais irritante para se desenvolver. No claro, acho que encontrei uma solução alternativa: defina a fonte da imagem como "" e depois volte à fonte original. Vou atualizar minha resposta.
Xavi
1
Você deve colocar a .attrlinha após as linhas .loade .error. Caso contrário, você corre o risco de a imagem carregar (ou encontrar um erro) antes que esses retornos de chamada sejam adicionados e eles não serão chamados.
Callum
19
O @Xavi Chrome não é o navegador mais irritante para se desenvolver, tente desenvolver para o Internet Explorer 7 ou menos. Além de adicionar um parâmetro $ _GET ao carregamento da imagem, ele carrega uma nova imagem toda vez, como sugerido pelo Gromix.
SSH Esta
10
Os métodos .load()e .error()são confusos e agora preteridos, usam .on()e usam os eventos loade errorcomo.
precisa saber é o seguinte
235

Verifique as propriedades completee naturalWidth, nessa ordem.

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
fonte
1
Interessante, eu estava olhando para o post anterior e não percebi o que eles estavam fazendo! complete para o IE como naturalWidth não está definido no IE. Indo verificar agora.
William
3
Aparentemente, isso só funciona de maneira confiável na primeira vez. Se você alterar o src da imagem, pelo menos o safari mobile continuará relatando o primeiro valor para naturalWidth e complete.
giorgian
5
retornar img.completo && tipo de img.naturalWidth! = 'indefinido' && img.naturalWidth! = 0;
Adrian Seeley
5
@vsync, você provavelmente desejaria usar isso como uma verificação única e, se a imagem ainda não tiver sido carregada, configure um manipulador de eventos "load". Não deve haver necessidade de martelar a CPU executando essa verificação várias vezes.
precisa saber é o seguinte
2
Para os curiosos, isso é exatamente o que a biblioteca imagesLoaded vinculada abaixo faz. Assim, para um one-off uso, ir para ele: github.com/desandro/imagesloaded/blob/master/...
cincodenada
57

Com base no meu entendimento da Especificação HTML do W3C para o imgelemento , você poderá fazer isso usando uma combinação dos atributos completee naturalHeight, da seguinte forma:

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

A partir da especificação para o completeatributo:

O atributo IDL completo deve retornar true se alguma das seguintes condições for verdadeira:

  • O atributo src é omitido.
  • A tarefa final enfileirada pela origem da tarefa de rede depois que o recurso foi buscado foi enfileirada.
  • O elemento img está completamente disponível.
  • O elemento img está quebrado.

Caso contrário, o atributo deve retornar false.

Então, essencialmente, completeretorna true se a imagem terminou de carregar ou falhou ao carregar. Como queremos apenas o caso em que a imagem foi carregada com sucesso, também precisamos verificar o nauturalHeightatributo:

O IDL atribui naturalWidthe naturalHeightdeve retornar a largura e a altura intrínsecas da imagem, em pixels CSS, se a imagem estiver disponível, ou então 0.

E availableé definido assim:

Um img está sempre em um dos seguintes estados:

  • Indisponível - O agente do usuário não obteve nenhum dado de imagem.
  • Parcialmente disponível - O agente do usuário obteve alguns dados da imagem.
  • Completamente disponível - O agente do usuário obteve todos os dados da imagem e pelo menos as dimensões da imagem estão disponíveis.
  • Quebrado - O agente do usuário obteve todos os dados da imagem que pode, mas não pode nem decodificar a imagem o suficiente para obter as dimensões da imagem (por exemplo, a imagem está corrompida ou o formato não é suportado ou nenhum dado pode ser obtido) .

Quando um elemento img está no estado parcialmente disponível ou no estado completamente disponível, é dito que está disponível.

Portanto, se a imagem estiver "quebrada" (falha ao carregar), ela estará no estado quebrado, e não no estado disponível, assim naturalHeightserá 0.

Portanto, a verificação imgElement.complete && imgElement.naturalHeight !== 0deve nos dizer se a imagem foi carregada com sucesso.

Você pode ler mais sobre isso na especificação HTML do W3C para o imgelemento ou no MDN .

Ajedi32
fonte
1
Não trabalho é imagem é carregada com estilo "conteúdo: url"
deathangel908
1
Isso não parece funcionar no Firefox com imagens SVG, pois o navegador informa altura / largura naturais como 0. Bug relevante: bugzilla.mozilla.org/show_bug.cgi?id=1328124
leeb 11/11/19
20

Eu tentei de muitas maneiras diferentes e dessa maneira é a única que funcionou para mim

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

Você também pode adicionar uma função de retorno de chamada acionada assim que todas as imagens estiverem carregadas no DOM e prontas. Isso também se aplica a imagens adicionadas dinamicamente. http://jsfiddle.net/kalmarsh80/nrAPk/

Kal
fonte
jsfiddle link quebrado
Alex Karshin 29/04
1
Testei as leituras interessantes acima e elas falham entre testes em cache / não em cache em um punhado de navegadores comuns. Esta resposta é semelhante a outra, mas é a que eu implementei e testei agora, posso confirmar que funciona em: EdgeWin10, IE11Win8.1, Win7IE10, Win7IE9, iOS 10.2 Chrome, iOS 10.2 Safari, 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ão se esqueça de usar addEventListener / removeEventListener também: D
danjah
13

Use a imagesLoadedbiblioteca javascript .

Utilizável com Javascript simples e como um plugin jQuery.

Recursos:

Recursos

Josh Harrison
fonte
Isso funcionou perfeitamente para mim. função checkImages (imgs) {$ (imgs) .each (function () {$ (imgs) .imagesLoaded () .progress (função (instância, imagem) {if (image.isLoaded == false) {console.log (image .img.src + 'não foi encontrado.'); image.img.src = "/templates/img/no-image.jpg";}});}); }
Rooster242
1
parece haver MUITOS problemas em aberto que são os principais erros, e o desenvolvedor não parece muito alcançá-los. a partir de agora, isso é totalmente inutilizável em um ambiente de produção.
vsync 29/03
3
@vsync Você leu algumas das questões em aberto? Ele responde a quase todos eles, e a maioria parece ser casos imprevisíveis que poucos outros encontram. Eu nunca tive um problema com isso na produção.
Josh Harrison
1
sim, eu uso-me e às vezes não funciona, então eu usar um setTimeout para cobrir casos onde ele falhar
vsync
Há boas razões pelas quais alguém deseja usar o plugin imagesLoaded: a completepropriedade não parece ser claramente suportada: não é possível encontrar uma fonte confiável de informações sobre o suporte ao navegador. completeA propriedade também parece não ter uma especificação clara: a especificação HTML5 é a única que a menciona e ainda está em uma versão de rascunho no momento da gravação. Se você usa naturalWidthe naturalHeightapenas tem suporte para o IE9 +, por isso, para descobrir se a imagem está carregada, precisará de algum truque "inteligente" para fazê-la funcionar em navegadores antigos e verificar se o comportamento entre navegadores é consistente
Adrien Seja
8

Recuperar informações de elementos de imagem na página
Testar o trabalho no Chrome e Firefox
Trabalhando com o jsFiddle (abra o console para ver o resultado)

$('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);

});

Nota: Eu usei o jQuery , achei que isso pode ocorrer em javascript completo

Encontrei boas informações aqui OpenClassRoom -> este é um fórum francês

Julha
fonte
3

Detector de rede em tempo real - verifique o status da rede sem atualizar a página: (não é jquery, mas testado e 100% funciona: (testado no Firefox v25.0))

Código:

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

se a conexão for perdida, basta pressionar o botão Novamente.

Atualização 1: detecção automática sem atualizar a página:

<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
fonte
100%! E se o seu link de imagem estiver bloqueado por um proxy / firewall ou o servidor de imagem não estiver respondendo? Você ainda tem o funcionamento da rede :)
Sen Jacob
Isso carregará todas as imagens novamente do servidor, impedindo o cache (intencionalmente). Portanto, apenas para verificar, você está (pelo menos) duplicando a largura de banda para todas as suas imagens. Além disso, verifica apenas se a imagem existe no servidor e não se foi carregada em algum local específico. Também não há como saber quando cada imagem é carregada.
Marius Balčytis
3

Depois de ler as soluções interessantes nesta página, criei uma solução fácil de usar, altamente influenciada pela postagem de SLaks e Noyo, que parece estar funcionando em versões bastante recentes (no momento da escrita) do Chrome, IE, Firefox, Safari e Opera (tudo no Windows). Além disso, funcionou em um emulador de iPhone / iPad que usei.

Uma grande diferença entre essa solução e o SLaks e o post de Noyo é que essa solução verifica principalmente as propriedades naturalWidth e naturalHeight. Descobri que nas versões atuais do navegador, essas duas propriedades parecem fornecer os resultados mais úteis e consistentes.

Esse código retorna VERDADEIRO quando uma imagem é carregada completamente E com sucesso. Ele retorna FALSE quando uma imagem ainda não foi totalmente carregada OU ou não foi carregada.

Você precisa estar ciente de que essa função também retornará FALSE se a imagem for uma imagem de 0x0 pixel. Mas essas imagens são bastante incomuns, e não consigo pensar em um caso muito útil em que você gostaria de verificar se uma imagem de pixel 0x0 ainda foi carregada :)

Primeiro, anexamos uma nova função chamada "isLoaded" ao protótipo HTMLImageElement, para que a função possa ser usada em qualquer elemento da imagem.

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;

};

Então, sempre que precisarmos verificar o status de carregamento da imagem, basta chamar a função "isLoaded".

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

De acordo com o comentário de Giorgian na publicação de SLaks e Noyo, essa solução provavelmente só pode ser usada como uma verificação única no Safari Mobile se você planeja alterar o atributo SRC. Mas você pode contornar isso criando um elemento de imagem com um novo atributo SRC em vez de alterar o atributo SRC em um elemento de imagem existente.

data-dan
fonte
2

É assim que eu consegui trabalhar em vários navegadores usando uma combinação dos métodos acima (eu também precisava inserir imagens dinamicamente no 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');
    }
});

Nota: Você precisará fornecer um estado booleano válido para a variável isIE.

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

// Ou como um plug-in

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

// $(".myImage").isLoaded() 
KhaledDev
fonte
1

Pelo que entendi, a propriedade .complete não é padrão. Pode não ser universal ... Percebo que parece funcionar de maneira diferente nos versos do Firefox IE. Estou carregando uma série de imagens em javascript e verificando se está completa. No Firefox, isso parece funcionar muito bem. No IE, isso não ocorre porque as imagens parecem estar sendo carregadas em outro segmento. Funciona apenas se eu colocar um atraso entre a minha atribuição ao image.src e quando verificar a propriedade image.complete.

Usar image.onload e image.onerror também não funciona para mim, porque preciso passar um parâmetro para saber de qual imagem estou falando quando a função é chamada. Qualquer maneira de fazer isso parece falhar, porque na verdade parece passar a mesma função, não instâncias diferentes da mesma função. Portanto, o valor que passo para identificar a imagem sempre acaba sendo o último valor no loop. Não consigo pensar em nenhuma maneira de contornar esse problema.

No Safari e no Chrome, estou vendo a imagem.com completa verdadeira e a largura natural definida mesmo quando o console de erros mostra um 404 para essa imagem ... e eu a removi intencionalmente para testar isso. Mas o acima funciona bem para Firefox e IE.

user1018645
fonte
Hum, isso é interessante. Importa-se de postar um exemplo de código para que eu queira tentar algumas coisas?
Xavi
1

Este trecho de código me ajudou a corrigir problemas de cache do navegador:

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

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

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

Quando o cache do navegador está desativado, apenas este código não funciona:

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

para fazer funcionar, você deve adicionar:

.each(function() {
     if($(this).prop('complete')) $(this).load();
});
Frank
fonte
0

Usando este JavaScriptcódigo, você pode verificar se a imagem foi carregada ou não com sucesso.

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

Experimente isso

Ajay Gupta
fonte
0

Eu tive muitos problemas com o carregamento completo de uma imagem e o EventListener.

O que quer que eu tenha tentado, os resultados não eram confiáveis.

Mas então eu encontrei a solução. Tecnicamente, não é agradável, mas agora nunca tive uma falha no carregamento da imagem.

O que eu fiz:

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

Em vez de carregar a imagem uma vez, basta carregá-la uma segunda vez diretamente após a primeira vez e as duas executam o manipulador de eventos.

Todas as minhas dores de cabeça se foram!


A propósito: Vocês do stackoverflow já me ajudaram mais de cem vezes. Por isso, muito obrigado!

Scoobeedo Cool
fonte
0

Este funcionou bem para mim :)

$('.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
fonte