¿Cómo crear una devolución de llamada de JavaScript para saber cuándo se carga una imagen?

136

Quiero saber cuándo una imagen ha terminado de cargarse. ¿Hay alguna manera de hacerlo con una devolución de llamada?

Si no, ¿hay alguna manera de hacerlo?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
2
github.com/desandro/imagesloaded - Amigos, revisen este paquete.
mangatinanda

Respuestas:

159

.complete + devolución de llamada

Este es un método compatible con los estándares sin dependencias adicionales, y no espera más de lo necesario:

var img = document.querySelector('img')

function loaded() {
  alert('loaded')
}

if (img.complete) {
  loaded()
} else {
  img.addEventListener('load', loaded)
  img.addEventListener('error', function() {
      alert('error')
  })
}

Fuente: http://www.html5rocks.com/en/tutorials/es6/promises/

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
44
¿Puede salir mal si la imagen se completa entre la img.completellamada y la addEventListenerllamada?
Thomas Ahle
@ThomasAhle No soy un experto, pero eso parece posible. Veamos si alguien tiene una solución.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Supongo que sólo sería un problema para código paralelo, que la mayoría Javascript probablemente no es ..
Thomas Ahle
44
@ThomasAhle No puede, porque el navegador solo disparará el evento de carga cuando la cola de eventos se hila. Dicho esto, el loadoyente del evento debe estar en una elsecláusula, ya que img.completepuede hacerse realidad antes de loadque se active el evento, por lo tanto, si no fuera así, podría haber loadedllamado dos veces (tenga en cuenta que es probable que esto cambie de manera tal que img.completesolo se convierta en realidad cuando el evento incendios).
gsnedders
72

Image.onload () a menudo funcionará.

Para usarlo, deberá asegurarse de vincular el controlador de eventos antes de establecer el atributo src.

Enlaces relacionados:

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

keparo
fuente
26
FYI: De acuerdo con las especificaciones del W3C, la carga no es un evento válido para elementos IMG. Obviamente, los navegadores lo admiten, pero si le importan las especificaciones y no está 100% seguro de que todos los navegadores a los que desea apuntar lo respalden, es posible que desee repensarlo o al menos tenerlo en cuenta.
Jason Bunting
3
¿Por qué esperar 5 segundos para configurar la fuente parece una mala idea?
2014
8
@quemeful por eso se llama "un ejemplo".
Diego Jancic
3
@JasonBunting ¿Qué estás viendo que te hace pensar que el loadevento no es válido? html.spec.whatwg.org/multipage/webappapis.html#handler-onload es la definición del onload controlador de eventos.
gsnedders
44
@gsnedders: se da cuenta, supongo, que cuando escribí ese comentario, me refería al estándar existente, no al que usted señaló, que es 4.5 años más nuevo. Si hubieras preguntado en ese entonces, podría haberlo señalado, tal vez. Tal es la naturaleza de la web, ¿verdad? Las cosas se ponen viejos o se mueven o se modifican, etc.
Jason Bunting
20

Puede usar la propiedad .complete de la clase de imagen Javascript.

Tengo una aplicación donde almaceno varios objetos de imagen en una matriz, que se agregarán dinámicamente a la pantalla, y a medida que se cargan, escribo actualizaciones en otro div en la página. Aquí hay un fragmento 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);
}
Jon DellOro
fuente
He usado un código similar en mi trabajo antes. Esto funciona bien en todos los navegadores.
Gabriel Hurley
2
El problema con la verificación completa es que a partir de IE9, los eventos OnLoad se disparan antes de que se carguen todas las imágenes y ahora es difícil encontrar un desencadenante para la función de verificación.
Gene Vincent
8

La vida es demasiado corta para 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="">

Idan Beker
fuente
1
Esta es una gran respuesta, pero no creo que necesite tanto código. Simplemente está haciendo que parezca confuso al agregar el srccon JS.
Brandon Benefield
1
El tiempo es una gran limitación en la programación. A partir de mi experiencia, escribir código legible (mientras sea largo) proporciona un gran beneficio de tiempo.
Idan Beker
¿Por qué almacenarías el src en una nueva variable solo para consumirlo en la siguiente línea? Si la brevedad es su objetivo, ese es un antipatrón. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620Hace el truco.
Josiah
3

Aquí está el equivalente de jQuery:

var $img = $('img');

if ($img.length > 0 && !$img.get(0).complete) {
   $img.on('load', triggerAction);
}

function triggerAction() {
   alert('img has been loaded');
}
Alexander Drobyshevsky
fuente
1

No es adecuado para 2008 cuando se hizo la pregunta, pero en estos días esto funciona bien para mí:

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

Estas funciones resolverán el problema, debe implementar la DrawThumbnailsfunción y tener una variable global para almacenar las imágenes. Me encanta hacer que esto funcione con un objeto de clase que tiene elThumbnailImageArray variable como miembro, ¡pero estoy luchando!

llamado como en 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 } };
}
Dave
fuente
11
La mayor parte de este código es irrelevante, incluida toda su addThumbnailImagesfunción. Reducirlo al código relevante y eliminaré el -1.
Justin Morgan
0

Si el objetivo es diseñar el img después de que el navegador haya procesado la imagen, debe:

const img = new Image();
img.src = 'path/to/img.jpg';

img.decode().then(() => {
/* set styles */
/* add img to DOM */ 
});

porque el navegador primero loads the compressed version of image, luego decodes it, finalmente paints. ya que no hay ningún evento para paintusted, debe ejecutar su lógica después de que el navegador tenga decodedla etiqueta img.

Sajad
fuente
-2

Si está utilizando React.js, puede hacer esto:

render() {

// ...

<img 
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}

src={item.src} key={item.key}
ref={item.key} />

// ...}

Dónde:

  • - onLoad (...) ahora llamará con algo como esto: {src: " https: //......png ", clave: "1"} puede usar esto como "clave" para saber qué imágenes se carga correctamente y que no.
  • - onError (...) es lo mismo pero para errores.
  • - el objeto "elemento" es algo como esto {clave: "..", src: ".."} que puede usar para almacenar la URL y la clave de las imágenes para usarlas en una lista de imágenes.

  • Miguel
    fuente