¿Cómo puedo verificar si hay una imagen de fondo cargada?

154

Quiero establecer una imagen de fondo en la etiqueta del cuerpo, luego ejecutar un código, como este:

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

¿Cómo puedo asegurarme de que la imagen de fondo esté completamente cargada?

Peter
fuente
44
Simplemente asigne la misma URL al Image()objeto que tiene onloadevento.
Shadow Wizard es Ear For You
2
asegúrese de enrollar la url en cssurl()
bluescrubbie

Respuestas:

274

prueba esto:

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

esto creará una nueva imagen en la memoria y usará el evento de carga para detectar cuándo se carga el src.

jcubic
fuente
10
Parece que la imagen se cargaría dos veces sin ningún motivo.
HyderA
49
@gAMBOOKa Se cargan una vez porque permanecen en la memoria del navegador. Esto es lo mismo, cuando coloca imágenes ocultas en la parte superior de su página y luego lo configura en CSS, por lo que las imágenes comienzan a descargarse antes del archivo css, se llama precarga.
jcubic
44
No estoy muy seguro, pero creo que te refieres al caché. No creo que haya algo como la memoria del navegador donde se almacenan los activos. Si se refiere a la memoria caché, recuerde que está agregando una solicitud HTTP adicional y es posible que todos los clientes no tengan habilitada la memoria caché.
HyderA
77
Ingrese esto en cualquier página que tenga 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)'); }))y verifique las solicitudes HTTP en Firebug. Si he abierto una página de parpadeo con esta imagen abierta en otra pestaña, no hace ninguna solicitud HTTP, solo muestra esta imagen al instante. y cuando borro el caché y lo ejecuto hubo una solicitud.
jcubic
26
Una comparación entre esta prueba y esta muestra que debe llamar .remove()al $('<img/>')objeto para evitar una pérdida de memoria. Debería ver un consumo de memoria estable en la primera prueba y un aumento de memoria en la segunda. Después de unas pocas horas de ejecución en Chrome 28, la primera prueba toma 80 MB y la segunda 270 MB.
benweet
23

Tengo un complemento jQuery llamado waitForImagesque puede detectar cuándo se han descargado las imágenes de fondo.

$('body')
  .css('background-image','url(http://picture.de/image.png)')
  .waitForImages(function() {
    alert('Background image done loading');
    // This *does* work
  }, $.noop, true);
alex
fuente
Este complemento también es excelente para poder mostrar el progreso de carga utilizando la eachdevolución de llamada.
Soviut
1
@alex, ¿cómo debo verificar cada imagen de fondo para cada elemento en una clase? Intenté esto pero no parece hacerlo bien. $ ('. user_main_photo_thumb'). waitForImages (function () {$ (this) .parents ('. photoThumbFrame'). delay (1000) .slideDown ();}, function (loaded, count, success) {});
Relm
@Relm No lo estás usando correctamente. La segunda devolución de llamada es por imagen. Además, delay()no funciona así.
alex
16

Algo como esto:

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
fuente
hola ... esto parece funcionar, aunque configuré bg.replace en bg.replace( ... , my_src ). Pero mi pregunta es: una vez que se carga $ ('<img>'), qué sucede exactamente con eso <img>... Quiero decir que no es real, es solo un marcador de posición ficticio, ¿verdad?
dsdsdsdsd
Correcto. El <img>nunca se inserta en el DOM; solo se usa para "engañar" al navegador para que cargue el archivo de imagen en la caché.
Colin
útil si no quieres invocar jQuery
vwvan
15

No hay devoluciones de llamada JS para activos CSS.

Adrian Pacala
fuente
3
Gracias por la rápida respuesta. ¿Alguna idea para una solución alternativa?
Peter
pero hay una solución JS para aquellos que buscan stackoverflow.com/questions/5057990/…
godblessstrawberry
8

solución JS pura que agregará un precargador, establecerá la imagen de fondo y luego la configurará para la recolección de basura junto con su detector de eventos :

Version corta:

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

Un poco más con buena transición de opacidad:

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
fuente
3
Solución infravalorada.
Tom Thomson
1
@TomThomson gracias Tom, encontré que la transición de la imagen no funcionaba correctamente, la arreglé
godblessstrawberry
6

Aquí hay un pequeño complemento que hice para permitirle hacer exactamente esto, también funciona en múltiples imágenes de fondo y múltiples elementos:

Leer el artículo:

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

o vaya directamente al código del complemento:

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

Tan solo incluya el complemento y luego instálelo en el elemento:

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

Obviamente descargue el complemento y guárdelo en su propio alojamiento.

Por defecto, agrega una clase adicional "bg-loaded" a cada elemento coincidente una vez que se carga el fondo, pero puede cambiarlo fácilmente pasándole una función 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>

Aquí hay un codepen que demuestra que funciona.

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

Jon Catmull
fuente
3

He encontrado una solución que funcionó mejor para mí y que tiene la ventaja de ser utilizable con varias imágenes (el caso no se ilustra en este ejemplo).

De la respuesta de @ adeneo a esta pregunta :

Si tiene un elemento con una imagen de fondo, como este

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

Puede esperar a que se cargue el fondo al obtener la URL de la imagen y usarla para un objeto de imagen en javascript con un controlador de carga

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

Hice un truco de javascript puro para hacer esto posible.

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

O

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

css:

.image_error {
    display: none;
}
Gino
fuente