Detectar cuando una imagen no se carga en Javascript


Hay una manera de determinar si una ruta de imagen conduce a una imagen real, es decir, detectar cuando una imagen no se carga en Javascript.

Para una aplicación web, estoy analizando un archivo xml y creando dinámicamente imágenes HTML a partir de una lista de rutas de imagen. Es posible que algunas rutas de imagen ya no existan en el servidor, por lo que quiero fallar correctamente al detectar qué imágenes no se cargan y eliminar ese elemento HTML img.

Tenga en cuenta que las soluciones de jQuery no se podrán usar(el jefe no quiere usar jQuery, sí, sé que no me hagas empezar). Conozco una forma en jQuery de detectar cuándo se carga una imagen, pero no si falló.

Mi código para crear elementos img, pero ¿cómo puedo detectar si la ruta img conduce a una imagen fallida al cargar?

var imgObj = new Image();  // document.createElement("img");
imgObj.src = src;
Author: Damjan Pavlica, 2012-03-22

7 answers

Puedes probar el siguiente código. Sin embargo, no puedo responder por la compatibilidad del navegador, por lo que tendrá que probar eso.

function testImage(URL) {
    var tester=new Image();
    tester.onload=imageFound;
    tester.onerror=imageNotFound;
    tester.src=URL;
}

function imageFound() {
    alert('That image is found and loaded');
}

function imageNotFound() {
    alert('That image was not found.');
}

testImage("http://foo.com/bar.jpg");

Y mis simpatías por el jefe resistente a jQuery!

 79
Author: Nikhil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-03 14:48:16

La respuesta es agradable, pero introduce un problema. Siempre que asigne onload o onerror directamente, puede reemplazar la devolución de llamada que se asignó anteriormente. Es por eso que hay un buen método que "registra el oyente especificado en el EventTarget en el que se llama" como dicen en MDN. Puede registrar tantos oyentes como desee en el mismo evento.

Permítanme reescribir un poco la respuesta.

function testImage(url) {
    var tester = new Image();
    tester.addEventListener('load', imageFound);
    tester.addEventListener('error', imageNotFound);
    tester.src = url;
}

function imageFound() {
    alert('That image is found and loaded');
}

function imageNotFound() {
    alert('That image was not found.');
}

testImage("http://foo.com/bar.jpg");

Porque el proceso de carga de recursos externos es asíncrono, sería aún mejor usar JavaScript moderno con promesas, como las siguientes.

function testImage(url) {

    // Define the promise
    const imgPromise = new Promise(function imgPromise(resolve, reject) {

        // Create the image
        const imgElement = new Image();

        // When image is loaded, resolve the promise
        imgElement.addEventListener('load', function imgOnLoad() {
            resolve(this);
        });

        // When there's an error during load, reject the promise
        imgElement.addEventListener('error', function imgOnError() {
            reject();
        })

        // Assign URL
        imgElement.src = url;

    });

    return imgPromise;
}

testImage("http://foo.com/bar.jpg").then(

    function fulfilled(img) {
        console.log('That image is found and loaded', img);
    },

    function rejected() {
        console.log('That image was not found');
    }

);
 26
Author: emil.c,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-27 09:37:51

Esto:

<img onerror="this.src='/images/image.png'" src="...">
 10
Author: Rafael Martins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-15 21:39:25
/**
 * Tests image load.
 * @param {String} url
 * @returns {Promise}
 */
function testImageUrl(url) {
  return new Promise(function(resolve, reject) {
    var image = new Image();
    image.addEventListener('load', resolve);
    image.addEventListener('error', reject);
    image.src = url;
  });
}

return testImageUrl(imageUrl).then(function imageLoaded(e) {
  return imageUrl;
})
.catch(function imageFailed(e) {
  return defaultImageUrl;
});
 4
Author: holmberd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-03 02:00:36

Aquí hay una función que escribí para otra respuesta: Url de imagen de Javascript Verificar. No se si es exactamente lo que necesitas, pero usa las diversas técnicas que usarías, que incluyen manejadores para onload, onerror, onabort y un tiempo de espera general.

Debido a que la carga de la imagen es asincrónica, llama a esta función con su imagen y luego llama a su devolución de llamada algún tiempo después con el resultado.

 3
Author: jfriend00,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:07

JQuery + CSS para img

Con jQuery esto funciona para mí:

$('img').error(function() {
    $(this).attr('src', '/no-img.png').addClass('no-img');
});

Y puedo usar esta imagen en todas partes en mi sitio web independientemente del tamaño de la misma con la siguiente propiedad CSS3:

img.no-img {
    object-fit: cover;
    object-position: 50% 50%;
}

CONSEJO 1 : utilice una imagen cuadrada de al menos 800 x 800 píxeles.

CONSEJO 2: para usar con retrato de personas, use object-position: 20% 50%;

CSS solo para background-img

Para las imágenes de fondo faltantes, también agregué lo siguiente en cada background-image declaración:

background-image: url('path-to-image.png'), url('no-img.png');

NOTA : no funciona para imágenes transparentes.

Lado del servidor Apache

Otra solución es detectar la imagen faltante con Apache antes de enviarla al navegador y volver a colocarla por el valor predeterminado no-img.contenido png.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} /images/.*\.(gif|jpg|jpeg|png)$
RewriteRule .* /images/no-img.png [L,R=307]
 1
Author: Meloman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-23 12:22:25

Justo como abajo:

var img = new Image(); 
img.src = imgUrl; 

if (!img.complete) {

//has picture
}
else //not{ 

}
 -17
Author: JamesChen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-22 04:10:59