javascript - code - jquery create element
jQuery/JavaScript para reemplazar imágenes rotas (30)
Tengo una página web que incluye un montón de imágenes. A veces, la imagen no está disponible, por lo que una imagen rota se muestra en el navegador del cliente.
¿Cómo uso jQuery para obtener el conjunto de imágenes, filtrarlo a imágenes rotas y reemplazar el src?
- Pensé que sería más fácil hacer esto con jQuery, pero resultó mucho más fácil simplemente usar una solución de JavaScript puro, es decir, la proporcionada por Prestaul.
A veces no es factible utilizar el evento de error
, por ejemplo, porque está intentando hacer algo en una página que ya está cargada, como cuando está ejecutando código a través de la consola, un marcador o un script cargado de forma asíncrona. En ese caso, comprobar que img.naturalWidth
y img.naturalHeight
son 0 parece hacer el truco.
Por ejemplo, aquí hay un fragmento para recargar todas las imágenes rotas desde la consola:
$$("img").forEach(img => {
if (!img.naturalWidth && !img.naturalHeight) {
img.src = img.src;
}
}
Al usar la respuesta de Prestaul , agregué algunos controles y prefiero usar el método jQuery.
<img src="image1.png" onerror="imgError(this,1);"/>
<img src="image2.png" onerror="imgError(this,2);"/>
function imgError(image, type) {
if (typeof jQuery !== ''undefined'') {
var imgWidth=$(image).attr("width");
var imgHeight=$(image).attr("height");
// Type 1 puts a placeholder image
// Type 2 hides img tag
if (type == 1) {
if (typeof imgWidth !== ''undefined'' && typeof imgHeight !== ''undefined'') {
$(image).attr("src", "http://lorempixel.com/" + imgWidth + "/" + imgHeight + "/");
} else {
$(image).attr("src", "http://lorempixel.com/200/200/");
}
} else if (type == 2) {
$(image).hide();
}
}
return true;
}
Aquí hay un ejemplo utilizando el objeto de imagen HTML5 envuelto por JQuery. Llame a la función de carga para la URL de la imagen principal y si esa carga causa un error, reemplace el atributo src de la imagen con una URL de respaldo.
function loadImageUseBackupUrlOnError(imgId, primaryUrl, backupUrl) {
var $img = $(''#'' + imgId);
$(new Image()).load().error(function() {
$img.attr(''src'', backupUrl);
}).attr(''src'', primaryUrl)
}
<img id="myImage" src="primary-image-url"/>
<script>
loadImageUseBackupUrlOnError(''myImage'',''primary-image-url'',''backup-image-url'');
</script>
Aquí hay una manera rápida y sucia de reemplazar todas las imágenes rotas, y no hay necesidad de cambiar el código HTML;)
$("img").each(function(){
var img = $(this);
var image = new Image();
image.src = $(img).attr("src");
var no_image = "https://dummyimage.com/100x100/7080b5/000000&text=No+image";
if (image.naturalWidth == 0 || image.readyState == ''uninitialized''){
$(img).unbind("error").attr("src", no_image).css({
height: $(img).css("height"),
width: $(img).css("width"),
});
}
});
Aquí hay una solución independiente:
$(window).load(function() {
$(''img'').each(function() {
if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
// image was broken, replace with your new image
this.src = ''http://www.tranism.com/weblog/images/broken_ipod.gif'';
}
});
});
Creé un fiddle para reemplazar la imagen rota usando el evento "onerror". Esto puede ayudarte.
//the placeholder image url
var defaultUrl = "url(''https://sadasd/image02.png'')";
$(''div'').each(function(index, item) {
var currentUrl = $(item).css("background-image").replace(/^url/([''"](.+)[''"]/)/, ''$1'');
$(''<img>'', {
src: currentUrl
}).on("error", function(e) {
$this = $(this);
$this.css({
"background-image": defaultUrl
})
e.target.remove()
}.bind(this))
})
Creo que esto es lo que jQuery.Preload : jQuery.Preload
Aquí está el código de ejemplo de la demostración, usted especifica las imágenes cargadas y no encontradas y está todo listo:
$(''#images img'').preload({
placeholder:''placeholder.jpg'',
notFound:''notfound.jpg''
});
Creo que tengo una forma más elegante con la delegación de eventos y la captura de eventos en el error
window
, incluso cuando la imagen de copia de seguridad no se carga.
img {
width: 100px;
height: 100px;
}
<script>
window.addEventListener(''error'', windowErrorCb, {
capture: true
}, true)
function windowErrorCb(event) {
let target = event.target
let isImg = target.tagName.toLowerCase() === ''img''
if (isImg) {
imgErrorCb()
return
}
function imgErrorCb() {
let isImgErrorHandled = target.hasAttribute(''data-src-error'')
if (!isImgErrorHandled) {
target.setAttribute(''data-src-error'', ''handled'')
target.src = ''backup.png''
} else {
//anything you want to do
console.log(target.alt, ''both origin and backup image fail to load!'');
}
}
}
</script>
<img id="img" src="error1.png" alt="error1">
<img id="img" src="error2.png" alt="error2">
<img id="img" src="https://i.stack.imgur.com/ZXCE2.jpg" alt="avatar">
La cuestión es :
Ponga el código en la
head
y ejecute como el primer script en línea. Por lo tanto, escuchará los errores que suceden después del guión.Utilice la captura de eventos para detectar los errores, especialmente para aquellos eventos que no hacen burbujas.
Utilice la delegación de eventos que evita los eventos de enlace en cada imagen.
Asigne un atributo al elemento
img
error después de proporcionarles unbackup.png
para evitar la desaparición delbackup.png
y el bucle infinito subsiguiente como se muestra a continuación
img error-> backup.png-> error-> backup.png-> error -> ,,,,,
En caso de que alguien como yo intente adjuntar el evento de error
a una etiqueta img
HTML dinámica, me gustaría señalar que hay un problema:
Al parecer, los eventos de error img
no burbujean en la mayoría de los navegadores, al contrario de lo standard dice el standard .
Entonces, algo como lo siguiente no funcionará :
$(document).on(''error'', ''img'', function () { ... })
Espero que esto sea de ayuda para otra persona. Ojalá hubiera visto esto aquí en este hilo. Pero, no lo hice. Entonces, lo estoy agregando
Encontré esta publicación mientras miraba esta otra publicación SO . A continuación hay una copia de la respuesta que di allí.
Sé que este es un hilo antiguo, pero React se ha vuelto popular y, quizás, alguien que usa React vendrá aquí en busca de una respuesta al mismo problema.
Entonces, si está utilizando React, puede hacer algo como lo siguiente, que fue una respuesta original proporcionada por Ben Alpert del equipo de React here
getInitialState: function(event) {
return {image: "http://example.com/primary_image.jpg"};
},
handleError: function(event) {
this.setState({image: "http://example.com/failover_image.jpg"});
},
render: function() {
return (
<img onError={this.handleError} src={src} />;
);
}
Esta es una técnica de mierda, pero está bastante garantizada:
<img ... onerror="this.parentNode.removeChild(this);">
Este es JavaScript, debe ser compatible con todos los navegadores y se entrega sin el feo marcado onerror=""
:
var sPathToDefaultImg = ''http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png'',
validateImage = function( domImg ) {
oImg = new Image();
oImg.onerror = function() {
domImg.src = sPathToDefaultImg;
};
oImg.src = domImg.src;
},
aImg = document.getElementsByTagName( ''IMG'' ),
i = aImg.length;
while ( i-- ) {
validateImage( aImg[i] );
}
Esto me ha estado frustrando por años. Mi corrección de CSS establece una imagen de fondo en el img
. Cuando una imagen dinámica src
no se carga en el primer plano, un marcador de posición es visible en el bg del img
. Esto funciona si sus imágenes tienen un tamaño predeterminado (por ejemplo, height
, height
min-height
, width
y / o min-width
).
Verás el icono de la imagen rota pero es una mejora. Probado hasta IE9 con éxito. iOS Safari y Chrome ni siquiera muestran un icono roto.
.dynamicContainer img {
background: url(''/images/placeholder.png'');
background-size: contain;
}
Agrega una pequeña animación para que src
cargue sin un parpadeo de fondo Chrome se desvanece en el fondo sin problemas, pero el escritorio de Safari no.
.dynamicContainer img {
background: url(''/images/placeholder.png'');
background-size: contain;
-webkit-animation: fadein 1s;
animation: fadein 1s;
}
@-webkit-keyframes fadein {
0% { opacity: 0.0; }
50% { opacity: 0.5; }
100% { opacity: 1.0; }
}
@keyframes fadein {
0% { opacity: 0.0; }
50% { opacity: 0.5; }
100% { opacity: 1.0; }
}
Mejor llamada usando
jQuery(window).load(function(){
$.imgReload();
});
Porque el uso de document.ready
no implica necesariamente que se carguen las imágenes, solo el HTML. Por lo tanto, no hay necesidad de una llamada retrasada.
Mientras el OP buscaba reemplazar el SRC, estoy seguro de que muchas personas que intentan responder a esta pregunta solo desean ocultar la imagen rota, en cuyo caso esta solución simple funcionó muy bien para mí:
<img src="someimage.jpg" onerror="this.style.display=''none'';" />
No estoy seguro de que exista una forma mejor, pero puedo pensar en un truco para obtenerlo. Podría publicar Ajax en la URL img y analizar la respuesta para ver si la imagen realmente regresó. Si regresó como un 404 o algo así, intercambie el img. Aunque espero que esto sea bastante lento.
No pude encontrar un script que se adapte a mis necesidades, por lo que hice una función recursiva para buscar imágenes rotas e intentar recargarlas cada cuatro segundos hasta que se solucionen.
Lo limité a 10 intentos como si no estuviera cargado, entonces la imagen podría no estar presente en el servidor y la función entraría en un bucle infinito. Aunque todavía estoy probando. Siéntete libre de pellizcarlo :)
var retries = 0;
$.imgReload = function() {
var loaded = 1;
$("img").each(function() {
if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
var src = $(this).attr("src");
var date = new Date();
$(this).attr("src", src + "?v=" + date.getTime()); //slightly change url to prevent loading from cache
loaded =0;
}
});
retries +=1;
if (retries < 10) { // If after 10 retries error images are not fixed maybe because they
// are not present on server, the recursion will break the loop
if (loaded == 0) {
setTimeout(''$.imgReload()'',4000); // I think 4 seconds is enough to load a small image (<50k) from a slow server
}
// All images have been loaded
else {
// alert("images loaded");
}
}
// If error images cannot be loaded after 10 retries
else {
// alert("recursion exceeded");
}
}
jQuery(document).ready(function() {
setTimeout(''$.imgReload()'',5000);
});
Puedes usar la propia búsqueda de GitHub para esto:
Frontend: https://github.com/github/fetch
o para Backend, una versión de Node.js: https://github.com/bitinn/node-fetch
fetch(url)
.then(function(res) {
if (res.status == ''200'') {
return image;
} else {
return placeholder;
}
}
Edición: este método reemplazará a XHR y, supuestamente, ya ha estado en Chrome. Para cualquier persona que lea esto en el futuro, es posible que no necesite la biblioteca mencionada anteriormente.
Puro JS. Mi tarea fue: si la imagen ''bl-once.png'' está vacía -> inserte la primera imagen (que no tiene estado 404) de la lista de arreglos (en el directorio actual):
<img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)">
Tal vez necesita ser mejorado, pero:
var srcToInsertArr = [''empty1.png'', ''empty2.png'', ''needed.png'', ''notActual.png'']; // try to insert one by one img from this array
var path;
var imgNotFounded = true; // to mark when success
var replaceEmptyImage = {
insertImg: function (elem) {
if (srcToInsertArr.length == 0) { // if there are no more src to try return
return "no-image.png";
}
if(!/undefined/.test(elem.src)) { // remember path
path = elem.src.split("/").slice(0, -1).join("/"); // "http://localhost:63342/GetImage"
}
var url = path + "/" + srcToInsertArr[0];
srcToInsertArr.splice(0, 1); // tried 1 src
if(imgNotFounded){ // while not success
replaceEmptyImage.getImg(url, path, elem); // CALL GET IMAGE
}
},
getImg: function (src, path, elem) { // GET IMAGE
if (src && path && elem) { // src = "http://localhost:63342/GetImage/needed.png"
var pathArr = src.split("/"); // ["http:", "", "localhost:63342", "GetImage", "needed.png"]
var name = pathArr[pathArr.length - 1]; // "needed.png"
xhr = new XMLHttpRequest();
xhr.open(''GET'', src, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.status == 200) {
elem.src = src; // insert correct src
imgNotFounded = false; // mark success
}
else {
console.log(name + " doesn''t exist!");
elem.onerror();
}
}
}
}
};
Por lo tanto, insertará el ''needed.png'' correcto en mi fuente o ''no-image.png'' del directorio actual.
Resolví mi problema con estas dos funciones simples:
function imgExists(imgPath) {
var http = jQuery.ajax({
type:"HEAD",
url: imgPath,
async: false
});
return http.status != 404;
}
function handleImageError() {
var imgPath;
$(''img'').each(function() {
imgPath = $(this).attr(''src'');
if (!imgExists(imgPath)) {
$(this).attr(''src'', ''images/noimage.jpg'');
}
});
}
Si ha insertado su img
con innerHTML
, como: $("div").innerHTML = <img src="wrong-uri">
, puede cargar otra imagen si falla, por ejemplo, esto:
<script>
function imgError(img) {
img.error="";
img.src="valid-uri";
}
</script>
<img src="wrong-uri" onerror="javascript:imgError(this)">
¿Por qué se necesita javascript: _
? Debido a que los scripts inyectados en el DOM a través de las etiquetas de script en innerHTML
no se ejecutan en el momento en que se inyectan, debe ser explícito.
Si la imagen no se puede cargar (por ejemplo, porque no está presente en la URL suministrada), la URL de la imagen se cambiará a la predeterminada
Para más información sobre 1.8
$(''img'').on(''error'', function (e) {
$(this).attr(''src'', ''broken.png'');
});
Tengo el mismo problema. Este código funciona bien en mi caso.
// Replace broken images by a default img
$(''img'').each(function(){
if($(this).attr(''src'') === ''''){
this.src = ''/default_feature_image.png'';
}
});
Utilizo el código siguiente, que primero intenta encontrar el avatar del usuario actual según su ID de usuario, que en este caso es "123", y si no encuentra una imagen de avatar, el código de error cambia el img src a una imagen de marcador de posición.
<img src="avatars/users/123.png" onerror="this.src=''/ngTribeBase/src/assets/img/avatars/male.png''" />
Variante de CoffeeScript :
Lo hice para solucionar un problema con Turbolinks que causa que el método .error () se genere en Firefox a veces, aunque la imagen realmente está ahí.
$("img").error ->
e = $(@).get 0
$(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)
Yo uso el controlador de error
incorporado:
$("img").error(function () {
$(this).unbind("error").attr("src", "broken.gif");
});
error()
en desuso en 1.8 o superior.
jQuery 1.8
// If missing.png is missing, it is replaced by replacement.png
$( "img" )
.error(function() {
$( this ).attr( "src", "replacement.png" );
})
.attr( "src", "missing.png" );
jQuery 3
// If missing.png is missing, it is replaced by replacement.png
$( "img" )
.on("error", function() {
$( this ).attr( "src", "replacement.png" );
})
.attr( "src", "missing.png" );
Maneje el evento onError
para que la imagen reasigne su origen usando JavaScript:
function imgError(image) {
image.onerror = "";
image.src = "/images/noimage.gif";
return true;
}
<img src="image.png" onerror="imgError(this);"/>
O sin una función de JavaScript:
<img src="image.png" onError="this.onerror=null;this.src=''/images/noimage.gif'';" />
La siguiente tabla de compatibilidad enumera los navegadores que admiten el recurso de error:
$(window).bind(''load'', function() {
$(''img'').each(function() {
if((typeof this.naturalWidth != "undefined" &&
this.naturalWidth == 0 )
|| this.readyState == ''uninitialized'' ) {
$(this).attr(''src'', ''missing.jpg'');
}
}); })
Fuente: http://www.developria.com/2009/03/jquery-quickie---broken-images.html
;(window.jQuery || window.Zepto).fn.fallback = function (fallback) {
return this.one(''error'', function () {
var self = this;
this.src = (fallback || ''http://lorempixel.com/$width/$height'')
.replace(//$(/w+)/g, function (m, t) { return self[t] || ''''; });
});
};
Puede pasar una ruta de marcador de posición y acceder a ella todas las propiedades del objeto de imagen fallido a través de $*
:
$(''img'').fallback(''http://dummyimage.com/$widthx$height&text=$src'');