Compruebe si se carga una imagen (sin errores) con jQuery


224

Estoy usando JavaScript con la biblioteca jQuery para manipular miniaturas de imágenes contenidas en una lista desordenada. Cuando se carga la imagen, hace una cosa, cuando se produce un error, hace otra cosa. Estoy usando jQuery load()y error()métodos como eventos. Después de estos eventos, verifico el elemento DOM de la imagen para el .complete para asegurarme de que la imagen no esté cargada antes de que jQuery pueda registrar los eventos.

Funciona correctamente, excepto cuando se produce un error antes de que jQuery pueda registrar los eventos. La única solución que se me ocurre es utilizar el onerroratributo img para almacenar una "bandera" en algún lugar del mundo (o en el nodo en sí) que dice que falló para que jQuery pueda verificar esa "tienda / nodo" al verificar .complete.

¿Alguien tiene una mejor solución?

Editar: puntos principales en negrita y detalles adicionales a continuación: estoy verificando si una imagen está completa (también cargada) DESPUÉS de agregar un evento de carga y error en la imagen. De esa manera, si la imagen se cargó antes de que se registraran los eventos, todavía lo sabré. Si la imagen no se carga después de los eventos, los eventos se encargarán de ella cuando lo haga. El problema con esto es que puedo verificar fácilmente si una imagen ya está cargada, pero no puedo decir si ocurrió un error.


¿Cuándo registras los eventos de jQuery? Quizás algunos códigos ayuden. :)
okw

Hay mucho código, lo que dije anteriormente es solo una versión muy simple de lo que estoy haciendo. Llamo a los eventos después de que se carga el DOM. Se llama a un método para agregar eventos a las miniaturas.
William

Respuestas:


250

Otra opción es activar los eventos onloady / o onerrorcreando un elemento de imagen en memoria y estableciendo su srcatributo al srcatributo original de la imagen original. Aquí hay un ejemplo de lo que quiero decir:

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

¡Espero que esto ayude!


27
No parece estar funcionando tan bien como esperaba. En Google Chrome parece tener problemas cuando la imagen ya está en caché. No activa el método load (). :(
William

44
Ugg, tienes razón. Chrome es definitivamente el navegador más molesto para desarrollar. En el brillante, creo que podría haber encontrado una solución: establezca la fuente de la imagen en "" y luego vuelva a la fuente original. Actualizaré mi respuesta.
Xavi el

1
Debe poner la .attrlínea después de las líneas .loady .error. De lo contrario, corre el riesgo de que la imagen se cargue (o encuentre un error) antes de agregar esas devoluciones de llamada, y no se llamarán.
callum

19
@Xavi Chrome no es el navegador más molesto para desarrollar, intente desarrollar para Internet Explorer 7 o menos. Además de agregar un parámetro $ _GET a la carga de la imagen, cargará una nueva imagen cada vez, como sugirió Gromix.
SSH Este

10
Los .load()y .error()métodos son confusas y ahora en desuso, el uso .on()y el uso de las loady errorcomo eventos.
Firsh - LetsWP.io

235

Verifique las propiedades completey naturalWidth, en ese orden.

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

1
¡Interesante, estaba mirando esa publicación antes y no me di cuenta de que lo estaban haciendo! completo para IE ya que naturalWidth no está definido en IE. Voy a revisarlo ahora.
William

3
Aparentemente, esto solo funciona de manera confiable la primera vez. Si luego cambia el src de la imagen, al menos Safari Mobile continuará informando el primer valor para naturalWidth y completo.
giorgian

55
return img.complete && typeof img.naturalWidth! = 'undefined' && img.naturalWidth! = 0;
Adrian Seeley

55
@vsync probablemente quiera usar esto como una comprobación única, y si la imagen aún no se ha cargado, configure un controlador de eventos "cargar". No debería ser necesario martillar la CPU ejecutando esta verificación varias veces.
Michael Martin-Smucker

2
Para aquellos curiosos, esto es casi exactamente lo que hace la biblioteca imagesLoaded vinculada a continuación. Entonces, para un uso único, ve por él: github.com/desandro/imagesloaded/blob/master/…
cincodenada

57

Según mi comprensión de la Especificación HTML W3C para el imgelemento , debería poder hacer esto usando una combinación de los atributos completey naturalHeight, de esta manera:

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

De la especificación para el completeatributo:

El atributo IDL completo debe devolver verdadero si alguna de las siguientes condiciones es verdadera:

  • El atributo src se omite.
  • La tarea final que se pone en cola por el origen de la tarea de red una vez que el recurso se ha recuperado se ha puesto en cola.
  • El elemento img está completamente disponible.
  • El elemento img está roto.

De lo contrario, el atributo debe devolver falso.

Entonces, esencialmente, completedevuelve verdadero si la imagen ha terminado de cargarse o no se pudo cargar. Como solo queremos el caso en el que la imagen se cargó correctamente, también debemos verificar el nauturalHeightatributo:

Los atributos IDL naturalWidthy naturalHeightdeben devolver el ancho y la altura intrínsecos de la imagen, en píxeles CSS, si la imagen está disponible, o bien 0.

Y availablese define así:

Un img siempre está en uno de los siguientes estados:

  • No disponible : el agente de usuario no ha obtenido ningún dato de imagen.
  • Parcialmente disponible : el agente de usuario ha obtenido algunos de los datos de la imagen.
  • Completamente disponible : el agente de usuario ha obtenido todos los datos de la imagen y al menos las dimensiones de la imagen están disponibles.
  • Roto : el agente de usuario ha obtenido todos los datos de imagen que puede, pero ni siquiera puede decodificar la imagen lo suficiente como para obtener las dimensiones de la imagen (por ejemplo, la imagen está dañada o el formato no es compatible o no se pudieron obtener datos) .

Cuando un elemento img está en el estado parcialmente disponible o en el estado completamente disponible, se dice que está disponible.

Entonces, si la imagen está "rota" (no se pudo cargar), entonces estará en el estado roto, no en el estado disponible, por naturalHeightlo que será 0.

Por lo tanto, la comprobación imgElement.complete && imgElement.naturalHeight !== 0debería decirnos si la imagen se ha cargado correctamente.

Puede leer más sobre esto en la Especificación HTML del W3C para el imgelemento , o en MDN .


1
No funciona si la imagen se carga con el estilo "content: url"
deathangel908

1
Esto no parece funcionar en Firefox con imágenes SVG como el navegador informa de altura / anchura natural a ser 0. Relevante fallo: bugzilla.mozilla.org/show_bug.cgi?id=1328124
Leeb

20

Intenté muchas formas diferentes y esta es la única que funcionó para mí.

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

También puede agregar una función de devolución de llamada activada una vez que todas las imágenes se cargan en el DOM y están listas. Esto también se aplica a las imágenes agregadas dinámicamente. http://jsfiddle.net/kalmarsh80/nrAPk/


Enlace roto jsfiddle
Alex Karshin

1
He probado las lecturas interesantes anteriores y fallan entre las pruebas en caché / sin caché en un puñado de navegadores comunes. Esta respuesta es similar a otra, pero es la que implementé y probé hace un momento, puedo confirmar que funciona en: EdgeWin10, IE11Win8.1, Win7IE10, Win7IE9, iOS 10.2 Chrome, 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. No olvides usar addEventListener / removeEventListener también: D
danjah

13

Utiliza la imagesLoadedbiblioteca javascript .

Se puede usar con Javascript simple y como un complemento jQuery.

caracteristicas:

Recursos


Esto funcionó perfectamente para mí. función checkImages (imgs) {$ (imgs) .each (function () {$ (imgs) .imagesLoaded () .progress (function (instancia, imagen) {if (image.isLoaded == false) {console.log (image .img.src + 'no se pudo encontrar.'); image.img.src = "/templates/img/no-image.jpg";}});}); }
Rooster242

1
parece tener TONELADAS de problemas abiertos que son errores importantes, y el desarrollador no parece ponerse al día con ellos. a partir de ahora, esto es totalmente inutilizable en un entorno de producción.
vsync

3
@vsync ¿Has leído algunos de los temas abiertos? Él responde a casi todos ellos, y la mayoría parecen ser casos improductivos que pocos encuentran. Nunca he tenido un problema con esto en producción.
Josh Harrison el

1
Sí, lo uso yo mismo y, a veces, no funciona, así que uso un setTimeout para cubrir los casos en que falla
vsync

Hay buenas razones por las cuales uno quiere usar el complemento imagesLoaded: la completepropiedad no parece ser claramente compatible: no se puede encontrar una fuente confiable de información sobre el soporte del navegador. completeLa propiedad tampoco parece tener una especificación clara: la especificación HTML5 es la única que la menciona y todavía está en una versión borrador al momento de la escritura. Si usa naturalWidthy naturalHeightsolo tiene soporte para IE9 +, por lo que si lo usa para averiguar si la imagen está cargada, necesita un truco "inteligente" para que funcione en navegadores antiguos, y debe verificar que el comportamiento entre navegadores sea coherente
Adrien Ser

8

Recupere información de los elementos de imagen en la página
Prueba de trabajo en Chrome y Firefox
Working jsFiddle (abra su consola para ver el 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: utilicé jQuery , pensé que esto podría funcionar con javascript completo

Encuentro buena información aquí OpenClassRoom -> este es un foro francés


3

Detector de red en tiempo real: compruebe el estado de la red sin actualizar la página: (no es jquery, pero está probado y funciona al 100%: (probado en 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>

Si se pierde la conexión, simplemente presione el botón de nuevo.

Actualización 1: Detección automática sin actualizar la 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>

100%! ¿Qué sucede si su enlace de imagen está bloqueado por un proxy / firewall o si el servidor de imágenes no responde? Aún tienes la red funcionando :)
Sen Jacob

Esto cargará cada imagen una vez más desde el servidor, reventando el caché (intencionalmente). Entonces, solo para verificar, está (al menos) duplicando el ancho de banda para todas sus imágenes. Además, verifica solo si la imagen existe en el servidor, no si se cargó en algún lugar específico. Tampoco hay forma de saber cuándo se carga cada imagen.
Marius Balčytis

3

Después de leer las soluciones interesantes en esta página, creé una solución fácil de usar altamente influenciada por la publicación de SLaks y Noyo que parece estar funcionando en versiones bastante recientes (al momento de escribir) de Chrome, IE, Firefox, Safari y Opera (todo en Windows). Además, funcionó en un emulador de iPhone / iPad que utilicé.

Una diferencia importante entre esta solución y la publicación de SLaks y Noyo es que esta solución verifica principalmente las propiedades naturalWidth y naturalHeight. Descubrí que en las versiones actuales del navegador, esas dos propiedades parecen proporcionar los resultados más útiles y consistentes.

Este código devuelve VERDADERO cuando una imagen se ha cargado completamente Y con éxito. Devuelve FALSE cuando una imagen aún no se ha cargado completamente O no se ha podido cargar.

Una cosa que deberá tener en cuenta es que esta función también devolverá FALSE si la imagen es una imagen de 0x0 píxeles. Pero esas imágenes son bastante poco comunes, y no puedo pensar en un caso muy útil en el que desee comprobar si una imagen de 0x0 píxeles se ha cargado todavía :)

Primero adjuntamos una nueva función llamada "isLoaded" al prototipo HTMLImageElement, para que la función pueda usarse en cualquier elemento de imagen.

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;

};

Luego, cada vez que necesitemos verificar el estado de carga de la imagen, simplemente llamamos a la función "isLoaded".

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

Según el comentario de giorgian sobre la publicación de SLaks y Noyo, esta solución probablemente solo se puede usar como una comprobación única en Safari Mobile si planea cambiar el atributo SRC. Pero puede solucionarlo creando un elemento de imagen con un nuevo atributo SRC en lugar de cambiar el atributo SRC en un elemento de imagen existente.


2

Así es como lo hice funcionar en el navegador cruzado usando una combinación de los métodos anteriores (también necesitaba insertar imágenes dinámicamente en el 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: Deberá proporcionar un estado booleano válido para la variable isIE.


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

// O como un complemento

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

// $(".myImage").isLoaded() 

1

Según tengo entendido, la propiedad .complete no es estándar. Puede que no sea universal ... Me doy cuenta de que parece funcionar de manera diferente en los versos de Firefox IE. Estoy cargando varias imágenes en javascript y luego comprobando si está completo. En Firefox, esto parece funcionar muy bien. En IE, no lo hace porque las imágenes parecen estar cargando en otro hilo. Funciona solo si pongo un retraso entre mi asignación a image.src y cuando verifico la propiedad image.complete.

Usar image.onload e image.onerror tampoco funciona para mí, porque necesito pasar un parámetro para saber de qué imagen estoy hablando cuando se llama a la función. Cualquier forma de hacerlo parece fallar porque en realidad parece pasar la misma función, no diferentes instancias de la misma función. Entonces, el valor que paso para identificar la imagen siempre termina siendo el último valor en el bucle. No puedo pensar de ninguna manera alrededor de este problema.

En Safari y Chrome, veo que image.complete true y naturalWidth se configuran incluso cuando la consola de error muestra un 404 para esa imagen ... y eliminé intencionalmente esa imagen para probar esto. Pero lo anterior funciona bien para Firefox e IE.


Hmm, eso es interesante. ¿Te importaría publicar un ejemplo de código, así que quiero probar un par de cosas?
Xavi

1

Este fragmento de código me ayudó a solucionar los problemas de almacenamiento en caché del navegador:

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

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

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

Cuando el caché del navegador está deshabilitado, solo este código no funciona:

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

para que funcione tienes que agregar:

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

0

Con este JavaScriptcódigo, puede verificar que la imagen se haya cargado correctamente o no.

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

Prueba esto


0

Tuve muchos problemas con la carga completa de una imagen y EventListener.

Lo que sea que intenté, los resultados no fueron confiables.

Pero luego encontré la solución. Técnicamente no es agradable, pero ahora nunca tuve una carga de imagen fallida.

Lo que hice:

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

En lugar de cargar la imagen una vez, simplemente la cargo por segunda vez directamente después de la primera vez y ambas se ejecutan a través del controlador de eventos.

¡Todos mis dolores de cabeza se han ido!


Por cierto: ustedes de stackoverflow me ayudaron más de cien veces. Por esto muchas gracias!


0

Este funcionó bien para mí :)

$('.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');
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.