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?


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.


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

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

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


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>


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


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

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

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.