J'ai une page Web qui comprend un tas d'images. Parfois, l'image n'est pas disponible et une image endommagée s'affiche dans le navigateur du client.
Comment utiliser jQuery pour obtenir le jeu d'images, le filtrer en images brisées, puis remplacer le fichier src?
--Je pensais qu'il serait plus facile de faire cela avec jQuery, mais il s'est avéré beaucoup plus facile d'utiliser une solution purement JavaScript, c'est-à-dire celle fournie par Prestaul.
Gérez l'événement onError
pour que l'image réaffecte sa source à l'aide de JavaScript:
function imgError(image) {
image.onerror = "";
image.src = "/images/noimage.gif";
return true;
}
<img src="image.png" onerror="imgError(this);"/>
Ou sans fonction JavaScript:
<img src="image.png" onError="this.onerror=null;this.src='/images/noimage.gif';" />
Le tableau de compatibilité suivant répertorie les navigateurs prenant en charge la fonction d'erreur:
J'utilise le gestionnaire intégré error
:
$("img").error(function () {
$(this).unbind("error").attr("src", "broken.gif");
});
Edit: La méthode error()
est obsolète en jquery 1.8 et plus. Au lieu de cela, vous devriez utiliser .on("error")
à la place:
$("img").on("error", function () {
$(this).attr("src", "broken.gif");
});
Au cas où quelqu'un comme moi essaierait de lier l'événement error
à une balise HTML dynamique img
, j'aimerais signaler qu'il existe un inconvénient:
Apparemment img
événements d'erreur ne pas afficher de bulles dans la plupart des navigateurs, contrairement à ce que standard) dit.
Donc, quelque chose comme ce qui suit ne fonctionnera pas :
$(document).on('error', 'img', function () { ... })
J'espère que cela sera utile à quelqu'un d'autre. J'aurais aimé l'avoir vu ici dans ce fil. Mais je ne l'ai pas fait. Donc, je l'ajoute
Voici une solution autonome:
$(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';
}
});
});
Je crois que c'est ce que vous recherchez: jQuery.Preload
Voici l'exemple de code de la démo, vous spécifiez le chargement et les images non trouvées et vous êtes tous ensemble:
$('#images img').preload({
placeholder:'placeholder.jpg',
notFound:'notfound.jpg'
});
$(window).bind('load', function() {
$('img').each(function() {
if((typeof this.naturalWidth != "undefined" &&
this.naturalWidth == 0 )
|| this.readyState == 'uninitialized' ) {
$(this).attr('src', 'missing.jpg');
}
}); })
Source: http://www.developria.com/2009/03/jquery-quickie---broken-images.html
Alors que le PO cherchait à remplacer le SRC, je suis sûr que beaucoup de personnes qui ont répondu à cette question souhaiteraient peut-être seulement cacher l’image brisée, auquel cas cette solution simple a fonctionné à merveille pour moi:
<img src="img.jpg" onerror="this.style.display='none';" />
Voici un moyen simple et rapide de remplacer toutes les images brisées, et il n’est pas nécessaire de changer le code 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"),
});
}
});
Je ne pouvais pas trouver de script adapté à mes besoins. J'ai donc créé une fonction récursive pour rechercher les images brisées et essayer de les recharger toutes les quatre secondes jusqu'à ce qu'elles soient corrigées.
Je l'ai limité à 10 tentatives, car si l'image n'était pas chargée, l'image pourrait ne pas être présente sur le serveur et la fonction entrerait dans une boucle infinie. Je teste toujours bien. N'hésitez pas à le modifier :)
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);
});
C'est une technique de merde, mais c'est à peu près garanti:
<img ... onerror="this.parentNode.removeChild(this);">
Ceci est JavaScript, devrait être compatible avec tous les navigateurs et fonctionne sans le balisage moche 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] );
}
Vous pouvez utiliser le propre récupération de GitHub pour cela:
Frontend: https://github.com/github/fetch
ou pour Backend, une version de Node.js: https://github.com/bitinn/node-fetch
fetch(url)
.then(function(res) {
if (res.status == '200') {
return image;
} else {
return placeholder;
}
}
Edit: Cette méthode remplacera XHR et aurait déjà été utilisée dans Chrome. Ceux qui liront ceci à l’avenir n'auront peut-être pas besoin de la bibliothèque susmentionnée.
Si vous avez inséré votre img
avec innerHTML
, comme: $("div").innerHTML = <img src="wrong-uri">
, vous pouvez charger une autre image si elle ne parvient pas, par exemple, ceci:
<script>
function imgError(img) {
img.error="";
img.src="valid-uri";
}
</script>
<img src="wrong-uri" onerror="javascript:imgError(this)">
Pourquoi javascript: _
est-il nécessaire? Comme les scripts injectés dans le DOM via les balises de script dans innerHTML
ne sont pas exécutés au moment de leur injection, vous devez donc être explicite.
Voici un exemple d'utilisation de l'objet Image HTML5 enveloppé par JQuery. Appelez la fonction de chargement pour l'URL de l'image principale et si ce chargement provoque une erreur, remplacez l'attribut src de l'image par une URL de sauvegarde.
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>
J'ai créé un violon pour remplacer l'image brisée en utilisant l'événement "onerror". Cela peut vous aider.
//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))
})
En utilisant réponse de Prestaul , j'ai ajouté quelques vérifications et je préfère utiliser la méthode 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;
}
Mieux appeler en utilisant
jQuery(window).load(function(){
$.imgReload();
});
Parce que l'utilisation de document.ready
n'implique pas nécessairement que les images sont chargées, uniquement le code HTML. Ainsi, il n'y a pas besoin d'un appel retardé.
CoffeeScript variante:
Je l'ai fait pour résoudre un problème avec Turbolinks qui provoque la levée de la méthode .error () dans Firefox parfois même si l'image est vraiment là.
$("img").error ->
e = $(@).get 0
$(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)
Pure JS. Ma tâche était: si l'image 'bl-once.png' est vide -> insère la première (qui n'a pas le statut 404) image de la liste de tableaux (dans le répertoire en cours):
<img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)">
Peut-être faut-il l'améliorer, mais:
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();
}
}
}
}
};
Donc, il insérera le fichier "needed.png" correct dans mon src ou "no-image.png" à partir du répertoire en cours.
J'ai trouvé ce post en regardant cet autre SO post . Vous trouverez ci-dessous une copie de la réponse que j'ai donnée ici.
Je sais que c'est un vieux fil, mais React est devenu populaire et, peut-être, quelqu'un qui utilise React viendra ici chercher une réponse au même problème.
Donc, si vous utilisez React, vous pouvez faire quelque chose comme ci-dessous, qui était une réponse originale fournie par Ben Alpert de l'équipe React ici
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} />;
);
}
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" );
J'ai résolu mon problème avec ces deux fonctions 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');
}
});
}
Je ne sais pas s'il existe un meilleur moyen, mais je peux penser à un bidouillage pour l'obtenir - vous pouvez poster Ajax sur l'URL img et analyser la réponse pour voir si l'image est réellement revenue. Si elle revient comme une 404 ou quelque chose comme ça, échangez l'img. Bien que je m'attende à ce que ce soit assez lent.
Cela me frustre depuis des années. Mon correctif CSS définit une image d’arrière-plan sur le img
. Lorsqu'une image dynamique src
ne se charge pas au premier plan, un espace réservé est visible sur le bg de img
. Ceci fonctionne si vos images ont une taille par défaut (par exemple height
, min-height
, width
et/ou min-width
).
Vous verrez l'icône d'image brisée, mais c'est une amélioration. Testé à IE9 avec succès. iOS Safari et Chrome ne montrent même pas une icône cassée.
.dynamicContainer img {
background: url('/images/placeholder.png');
background-size: contain;
}
Ajoutez une petite animation pour donner à src
le temps de se charger sans scintillement de fond. Chrome s'estompe doucement à l'arrière-plan, mais pas Safari sur le bureau.
.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; }
}
Je pense avoir un moyen plus élégant de déléguer et de capturer des événements sur window
'error
même lorsque le chargement de l'image de sauvegarde échoue.
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">
Le point est:
Placez le code dans le head
et exécutez-le en tant que premier script en ligne. Donc, il va écouter les erreurs se produisent après le script.
Utilisez la capture d’événements pour détecter les erreurs, en particulier pour les événements qui ne font pas de bulles.
Utilisez la délégation d'événements qui évite de lier des événements sur chaque image.
Attribuez à l'attribut error img
un attribut après leur avoir attribué un backup.png
pour éviter la disparition de backup.png
et la boucle infinie suivante, comme ci-dessous:
img error-> backup.png-> error-> backup.png-> error -> ,
Si l'image ne peut pas être chargée (par exemple, parce qu'elle n'est pas présente dans l'URL fournie), l'URL de l'image sera remplacée par défaut,
Pour plus d'informations sur . Error ()
$('img').on('error', function (e) {
$(this).attr('src', 'broken.png');
});
;(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] || ''; });
});
};
Vous pouvez passer un chemin d’espace réservé et y accéder à toutes les propriétés de l’objet d’image défectueux via $*
:
$('img').fallback('http://dummyimage.com/$widthx$height&text=$src');
J'ai le même problème. Ce code fonctionne bien sur mon cas.
// Replace broken images by a default img
$('img').each(function(){
if($(this).attr('src') === ''){
this.src = '/default_feature_image.png';
}
});
Parfois, l’utilisation de l’événement error
n’est pas réalisable, par exemple. parce que vous essayez de faire quelque chose sur une page déjà chargée, par exemple lorsque vous exécutez du code via la console, un bookmarklet ou un script chargé de manière asynchrone. Dans ce cas, vérifier que img.naturalWidth
et img.naturalHeight
sont 0 semble correspondre à l'astuce.
Par exemple, voici un extrait permettant de recharger toutes les images brisées de la console:
$$("img").forEach(img => {
if (!img.naturalWidth && !img.naturalHeight) {
img.src = img.src;
}
}
Je trouve que cela fonctionne mieux. Si une image ne parvient pas à se charger la première fois, elle est complètement supprimée du DOM. L'exécution de console.clear()
garde la fenêtre de la console propre, car les erreurs 404 ne peuvent pas être omises avec des blocs try/catch.
$('img').one('error', function(err) {
// console.log(JSON.stringify(err, null, 4))
$(this).remove()
console.clear()
})