У меня есть веб-страница, которая содержит кучу изображений. Иногда изображение недоступно, поэтому в браузере клиента отображается разбитое изображение.
Как я могу использовать jQuery для получения набора изображений, отфильтровать его на разбитые изображения, а затем заменить src?
- Я думал, что было бы проще сделать это с помощью jQuery, но оказалось, что гораздо проще просто использовать чистое решение JavaScript, то есть то, что предоставляется Prestaul.
Обработайте событие onError
, чтобы изображение переназначало исходный код с помощью JavaScript:
function imgError(image) {
image.onerror = "";
image.src = "/images/noimage.gif";
return true;
}
<img src="image.png" onerror="imgError(this);"/>
Или без функции JavaScript:
<img src="image.png" onError="this.onerror=null;this.src='/images/noimage.gif';" />
В следующей таблице совместимости перечислены браузеры, поддерживающие функцию ошибки:
Я использую встроенный обработчик error
:
$("img").error(function () {
$(this).unbind("error").attr("src", "broken.gif");
});
error()
устарел в 1.8 или новее.
В случае, если кто-то вроде меня, пытается привязать событие error
к динамическому тегу HTML img
, я хотел бы указать, что есть catch:
По-видимому, img
события ошибок не пузырь в большинстве браузеров, вопреки тому, что стандарт.
Итак, что-то вроде следующего будет не работать:
$(document).on('error', 'img', function () { ... })
Надеюсь, это будет полезно кому-то другому. Хотелось бы, чтобы я видел это здесь в этой теме. Но я этого не сделал. Итак, я добавляю его
Вот отдельное решение:
$(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';
}
});
});
Я считаю, что это то, что вам нужно: jQuery.Preload
Вот пример кода из демонстрации, вы указываете загрузочные и не найденные изображения, и все вы настроены:
$('#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');
}
}); })
Источник: http://www.developria.com/2009/03/jquery-quickie---broken-images.html
В то время как OP надеялся заменить SRC, я уверен, что многие люди, сталкивающиеся с этим вопросом, могут только скрыть сбитое изображение, и в этом случае это простое решение отлично поработал у меня:
<img src="someimage.jpg" onerror="this.style.display='none';" />
Вот быстрый и грязный способ заменить все испорченные изображения, и нет необходимости менять 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"),
});
}
});
Это дерьмовая техника, но она в значительной степени гарантирована:
<img ... onerror="this.parentNode.removeChild(this);">
Я не смог найти script в соответствии с моими потребностями, поэтому я сделал рекурсивную функцию для проверки неработающих изображений и попыток перезагрузить их каждые четыре секунды, пока они не будут исправлены.
Я ограничил его до 10 попыток, как если бы он не был загружен, тогда изображение может отсутствовать на сервере, и функция войдет в бесконечный цикл. Я все еще тестирую. Не стесняйтесь настраивать его:)
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);
});
Вы можете использовать собственную выборку GitHub для этого:
Внешний вид: https://github.com/github/fetch
или для Backend, Node.js версия: https://github.com/bitinn/node-fetch
fetch(url)
.then(function(res) {
if (res.status == '200') {
return image;
} else {
return placeholder;
}
}
Изменить: этот метод заменит XHR и предположительно уже был в Chrome. Для тех, кто читает это в будущем, вам может не понадобиться упомянутая выше библиотека.
Это JavaScript, должен быть совместим с браузером, и обеспечивает без уродливой разметки 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] );
}
Чистый JS. Моя задача состояла в том, что если образ "bl-once.png" пуст → вставьте первый из них (который не имеет статуса 404) из списка массивов (в текущем каталоге):
<img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)">
Возможно, его нужно улучшить, но:
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();
}
}
}
}
};
Итак, он будет вставлять правильный "needed.png" в мой src или "no-image.png" из текущего каталога.
Вот пример использования объекта HTML5 Image, обернутого JQuery. Вызовите функцию загрузки для URL первичного изображения, и если эта загрузка вызывает ошибку, замените атрибут src изображения URL-адресом резервной копии.
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>
Я создал fiddle, чтобы заменить сломанное изображение с помощью события "onerror". Это может вам помочь.
//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))
})
Я нашел этот пост, смотря на эту другую публикацию SO. Ниже приведена копия ответа, который я дал там.
Я знаю, что это старый поток, но React стал популярным, и, возможно, кто-то, кто использует React, придет сюда искать ответ на ту же проблему.
Итак, если вы используете React, вы можете сделать что-то вроде ниже, что было ответом, предоставленным Бен Алпертом команды React здесь
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} />;
);
}
Если вы вставили img
с помощью innerHTML
, например: $("div").innerHTML = <img src="wrong-uri">
, вы можете загрузить другое изображение, если оно не выполняется, например:
<script>
function imgError(img) {
img.error="";
img.src="valid-uri";
}
</script>
<img src="wrong-uri" onerror="javascript:imgError(this)">
Почему требуется javascript: _
? Поскольку скрипты, введенные в DOM через теги script в innerHTML
, не запускаются во время их ввода, поэтому вы должны быть явным.
Используя ответ Prestaul, я добавил несколько проверок, и я предпочитаю использовать способ 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;
}
CoffeeScript вариант:
Я решил исправить проблему с Turbolinks, которая заставляет метод .error() подниматься в Firefox иногда даже несмотря на то, что изображение действительно там.
$("img").error ->
e = $(@).get 0
$(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)
Лучший вызов с использованием
jQuery(window).load(function(){
$.imgReload();
});
Поскольку использование document.ready
не требует, чтобы изображения загружались, только HTML. Таким образом, нет необходимости в отсроченном вызове.
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" );
Я решил проблему с этими двумя простыми функциями:
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');
}
});
}
Я не уверен, есть ли лучший способ, но я могу подумать о взломе, чтобы получить его - вы могли бы отправить Ajax на URL-адрес img и проанализировать ответ, чтобы увидеть, действительно ли изображение вернулось. Если он вернется как 404 или что-то еще, замените img. Хотя я ожидаю, что это будет довольно медленно.
Я думаю, что у меня более элегантный способ делегирования событий и захвата событий на window
error
, даже если резервное изображение не загружается.
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">
Точка:
Поместите код в head
и выполните его как первый встроенный script. Таким образом, он будет выслушивать ошибки после script.
Используйте захват событий, чтобы поймать ошибки, особенно для тех событий, которые не пузырятся.
Используйте делегирование событий, которое позволяет избежать привязки событий к каждому изображению.
Дайте элементу ошибки img
атрибут после предоставления им backup.png
, чтобы избежать исчезновения backup.png
и последующего бесконечного цикла, как показано ниже:
img error- > backup.png- > error- > backup.png- > error → ,,,
Если изображение не может быть загружено (например, поскольку оно отсутствует в указанном URL-адресе), URL-адрес изображения будет изменен по умолчанию,
Подробнее о .error()
$('img'). on ('error', function (e) {
$(this).attr('src', 'broken.png');
});Код>
Это меня расстраивало годами. Мое исправление CSS устанавливает фоновое изображение на img
. Когда динамическое изображение src
не загружается на передний план, на img
bg видна заполнитель. Это работает, если ваши изображения имеют размер по умолчанию (например, height
, min-height
, width
и/или min-width
).
Вы увидите значок сломанного изображения, но это улучшение. Протестировано до IE9 успешно. iOS Safari и Chrome даже не показывают сломанную иконку.
.dynamicContainer img {
background: url('/images/placeholder.png');
background-size: contain;
}
Добавьте немного анимации, чтобы дать время src
для загрузки без фонового мерцания. Chrome постепенно исчезает в фоновом режиме, но на рабочем столе Safari нет.
.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; }
}
;(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] || ''; });
});
};
Вы можете передать путь к заполнителю и получить в нем все свойства из объекта неудавшегося изображения через $*
:
$('img').fallback('http://dummyimage.com/$widthx$height&text=$src');
Иногда использование события error
не представляется возможным, например. потому что вы пытаетесь сделать что-то на уже загруженной странице, например, когда вы запускаете код через консоль, букмарклет или script загружается асинхронно. В этом случае проверка того, что img.naturalWidth
и img.naturalHeight
равна 0, кажется, делает трюк.
Например, здесь приведен фрагмент для перезагрузки всех сломанных изображений с консоли:
$$ ( "img" ). forEach (img = > { if (! img.naturalWidth &! img.naturalHeight) { img.src= img.src; }
}
Код>
У меня такая же проблема. Этот код хорошо работает в моем случае.
// Replace broken images by a default img
$('img').each(function(){
if($(this).attr('src') === ''){
this.src = '/default_feature_image.png';
}
});
Это решение является простым JavaScript, и оно должно быть совместимым с crossbrowser и поставляет без уродливой разметки 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] );
}
Я нашел, что это работает лучше всего, если какое-либо изображение не загружается в первый раз, оно полностью удаляется из DOM. Выполнение console.clear()
обеспечивает чистоту окна консоли, поскольку ошибки 404 нельзя пропустить с помощью блоков try/catch.
$('img').one('error', function(err) {
// console.log(JSON.stringify(err, null, 4))
$(this).remove()
console.clear()
})
Я использую приведенный ниже код, который сначала пытается найти текущий аватар пользователя на основе их идентификатора пользователя, который в этом случае равен "123", и если он не находит изображение аватара, код onerror изменяет img src на placeholder изображение.
<img src="avatars/users/123.png" onerror="this.src='/ngTribeBase/src/assets/img/avatars/male.png'" />