Como posso verificar se uma imagem de fundo está carregada?

154

Quero definir uma imagem de plano de fundo na tag body e, em seguida, executar um código - como este:

$('body').css('background-image','http://picture.de/image.png').load(function() {
    alert('Background image done loading');
    // This doesn't work
});

Como posso garantir que a imagem de plano de fundo esteja totalmente carregada?

Peter
fonte
4
Apenas atribua a mesma URL ao Image()objeto que possui onloadevento.
Shadow Wizard é Ear For You
2
certifique-se de envolver o css url emurl()
bluescrubbie 17/10/12

Respostas:

274

tente isto:

$('<img/>').attr('src', 'http://picture.de/image.png').on('load', function() {
   $(this).remove(); // prevent memory leaks as @benweet suggested
   $('body').css('background-image', 'url(http://picture.de/image.png)');
});

isso criará uma nova imagem na memória e usará o evento load para detectar quando o src é carregado.

jcubic
fonte
10
Parece que a imagem seria carregada duas vezes sem motivo.
HyderA
49
@gAMBOOKa Eles são carregados uma vez porque permanecem na memória do navegador. É o mesmo: quando você coloca imagens ocultas no topo da página e as define em CSS - para que as imagens sejam baixadas antes do arquivo css -, isso é chamado de pré-carregamento.
jcubic
4
Não tenho muita certeza, mas acho que você está se referindo ao cache. Eu não acho que exista algo como memória do navegador onde os ativos estão armazenados. Se você estiver se referindo ao cache, lembre-se de adicionar uma solicitação HTTP extra e todos os clientes podem não ter o cache ativado.
HyderA
7
Digite isso em qualquer página que possua jquery: javascript:void($('<img/>').attr('src', 'http://farm6.static.flickr.com/5049/5220175127_5693faf952.jpg').load(function() { $('html').css('background-image', 'url(http://farm6.static.flickr.com/5049/5220175127_5693faf952.jpg)'); }))e verifique as solicitações HTTP no Firebug. Se eu abri a página de cintilação com esta imagem aberta em outra guia, ela não faz nenhuma solicitação HTTP, apenas mostra esta imagem instantaneamente. e quando eu limpo o cache e o executo, houve uma solicitação.
jcubic
26
Uma comparação entre este teste e este mostra que você tem que chamar .remove()no $('<img/>')objeto para evitar uma fuga de memória. Você deve ver um consumo estável de memória no primeiro teste e um aumento de memória no segundo. Depois de algumas horas em execução no Chrome 28, o primeiro teste demora 80 MB e o segundo, 270 MB.
benweet
23

Eu tenho um plugin jQuery chamado waitForImagesque pode detectar quando as imagens de fundo foram baixadas.

$('body')
  .css('background-image','url(http://picture.de/image.png)')
  .waitForImages(function() {
    alert('Background image done loading');
    // This *does* work
  }, $.noop, true);
alex
fonte
Este plug-in também é ótimo para mostrar o progresso do carregamento usando o eachretorno de chamada.
Soviut
1
@ alex, como devo verificar cada imagem de fundo para cada elemento em uma classe? Eu tentei isso, mas não parece fazer direito. $ ('. user_main_photo_thumb'). waitForImages (function () {$ (this) .parents ('. photoThumbFrame'). delay (1000) .slideDown ();}, function (carregada, contagem, sucesso) {});
Relm
@Rm Você não está usando corretamente. O segundo retorno de chamada é por imagem. Além disso, delay()não funciona assim.
31416 alex
16

Algo assim:

var $div = $('div'),
  bg = $div.css('background-image');
  if (bg) {
    var src = bg.replace(/(^url\()|(\)$|[\"\'])/g, ''),
      $img = $('<img>').attr('src', src).on('load', function() {
        // do something, maybe:
        $div.fadeIn();
      });
  }
});
Colin
fonte
Olá ... isso parece funcionar, embora eu defina o bg.replace como bg.replace( ... , my_src ). Mas minha pergunta é: uma vez que o $ ('<img>') seja carregado, o que exatamente acontece com isso <img>... quero dizer, não é realmente real - é apenas um espaço reservado simulado, certo?
Dsdsdsdsd
Certo. O <img>nunca é inserido no DOM; é apenas usado para "enganar" o navegador para carregar o arquivo de imagem no cache.
Colin
útil se você não quiser chamar jQuery
vwvan
15

Não há retornos de chamada JS para ativos CSS.

Adrian Pacala
fonte
3
Obrigado pela resposta rápida. Alguma idéia para uma solução alternativa?
Peter Peter
mas não há solução JS para quem está olhando stackoverflow.com/questions/5057990/...
godblessstrawberry
8

solução JS pura que adicionará o pré-carregador, defina a imagem de plano de fundo e configure-a para a coleta de lixo junto com seu ouvinte de eventos :

Versão curta:

const imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
let bgElement = document.querySelector("body");
let preloaderImg = document.createElement("img");
preloaderImg.src = imageUrl;

preloaderImg.addEventListener('load', (event) => {
    bgElement.style.backgroundImage = `url(${imageUrl})`;
    preloaderImg = null;
});

Um pouco mais com boa transição de opacidade:

const imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
let bgElement = document.querySelector(".bg-lazy");
bgElement.classList.add("bg-loading");
let preloaderImg = document.createElement("img");
preloaderImg.src = imageUrl;

preloaderImg.addEventListener('load', (event) => {
  bgElement.classList.remove("bg-loading");
  bgElement.style.backgroundImage = `url(${imageUrl})`;
  preloaderImg = null;
});
.bg-lazy {
  height: 100vh;
  width: 100vw;
  transition: opacity 1s ease-out;
}

.bg-loading {
  opacity: 0;
}
<div class="bg-lazy"></div>

godblessstrawberry
fonte
3
Solução subestimada.
Tom Thomson
1
@ TomTomson obrigado Tom, achei que a transição da imagem não funcionava corretamente,
corrigi-
6

Aqui está um pequeno plugin que eu criei para permitir que você faça exatamente isso, ele também funciona em várias imagens de fundo e em vários elementos:

Leia o artigo:

http://catmull.uk/code-lab/background-image-loaded/

ou vá direto para o código do plugin:

http://catmull.uk/downloads/bg-loaded/bg-loaded.js

Portanto, inclua o plug-in e chame-o no elemento:

<script type="text/javascript" src="http://catmull.uk/downloads/bg-loaded/bg-loaded.js"></script>
<script type="text/javascript">
   $('body').bgLoaded();
</script>

Obviamente, baixe o plug-in e armazene-o em sua própria hospedagem.

Por padrão, ele adiciona uma classe "bg-loaded" adicional a cada elemento correspondente depois que o plano de fundo é carregado, mas você pode facilmente mudar isso passando uma função diferente como esta:

<script type="text/javascript" src="http://catmull.uk/downloads/bg-loaded/bg-loaded.js"></script>
<script type="text/javascript">
   $('body').bgLoaded({
      afterLoaded : function() {
         alert('Background image done loading');
      }
   });
</script>

Aqui está um codepen demonstrando seu funcionamento.

http://codepen.io/catmull/pen/Lfcpb

Jon Catmull
fonte
3

Eu localizei uma solução que funcionou melhor para mim e que tem a vantagem de ser utilizável com várias imagens (caso não ilustrado neste exemplo).

Da resposta de @ adeneo nesta pergunta :

Se você tiver um elemento com uma imagem de plano de fundo, assim

<div id="test" style="background-image: url(link/to/image.png)"><div>

Você pode esperar o carregamento do plano de fundo obtendo o URL da imagem e usando-o para um objeto de imagem em javascript com um manipulador de onload

var src = $('#test').css('background-image');
var url = src.match(/\((.*?)\)/)[1].replace(/('|")/g,'');

var img = new Image();
img.onload = function() {
    alert('image loaded');
}
img.src = url;
if (img.complete) img.onload();
Paperjuice
fonte
2

Eu fiz um truque de javascript puro para tornar isso possível.

<div class="my_background_image" style="background-image: url(broken-image.jpg)">
<img class="image_error" src="broken-image.jpg" onerror="this.parentElement.style.display='none';">
</div>

Ou

onerror="this.parentElement.backgroundImage = "url('image_placeHolder.png')";

css:

.image_error {
    display: none;
}
Gino
fonte