JQuery/JavaScript, чтобы заменить сломанные изображения
У меня есть веб-страница, которая включает в себя кучу изображений. Иногда изображение недоступно, поэтому в браузере клиента отображается разорванное изображение.
Как мне использовать jQuery, чтобы получить набор изображений, отфильтровать его до поврежденных изображений и заменить src?
- Я думал, что с jQuery было бы легче сделать это, но оказалось гораздо проще просто использовать чистое решение JavaScript, то есть то, которое предоставляет Prestaul.
33 ответа
Обрабатывать 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 и выше. Вместо этого вы должны использовать .on("error")
вместо:
$("img").on("error", function () {
$(this).unbind("error").attr("src", "broken.gif");
});
В случае, если кто-то, как я, пытается прикрепить error
событие в динамический HTML img
Я хотел бы отметить, что здесь есть одна загвоздка:
По-видимому 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
В то время как ОП искал замену 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);">
Я не смог найти скрипт, который бы соответствовал моим потребностям, поэтому я сделал рекурсивную функцию, чтобы проверять битые изображения и пытаться загружать их каждые четыре секунды, пока они не будут исправлены.
Я ограничил его до 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);
});
Это 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] );
}
Вы можете использовать собственный выбор 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. Для тех, кто читает это в будущем, вам может не понадобиться указанная выше библиотека.
Это расстраивало меня годами. Мое исправление 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; }
}
Если вы вставили 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 через теги сценариев в innerHTML
не запускаются во время их введения, поэтому вы должны быть явными.
Вот пример использования объекта 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>
Вариант 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.
<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;
}
Чистый 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();
}
}
}
}
};
Таким образом, он вставит правильный 'required.png' в мой src или 'no-image.png' из текущего каталога.
Я создал скрипку для замены испорченного изображения с помощью события "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} />;
);
}
Для разработчиков React:
<img
src={"https://urlto/yourimage.png"} // <--- If this image src fail to load, onError function will be called, where you can add placeholder image or any image you want to load
width={200}
alt={"Image"}
onError={(event) => {
event.target.onerror = "";
event.target.src = "anyplaceholderimageUrlorPath"
return true;
}}
/>
;(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');
Я решил свою проблему с помощью этих двух простых функций:
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');
}
});
}
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" );
Иногда используя error
событие неосуществимо, например, потому что вы пытаетесь что-то сделать на странице, которая уже загружена, например, когда вы запускаете код через консоль, букмарклет или скрипт, загруженный асинхронно. В этом случае, проверяя, что img.naturalWidth
а также img.naturalHeight
0, кажется, делают свое дело.
Например, вот фрагмент для перезагрузки всех неработающих изображений из консоли:
$$("img").forEach(img => {
if (!img.naturalWidth && !img.naturalHeight) {
img.src = img.src;
}
}
Я думаю, что у меня есть более элегантный способ с делегированием событий и захватом событий на window
"s 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://stackru.com/images/416a8632098979a0170753c6c8af2b0b6acc2b8a.jpg" alt="avatar">
Дело в том:
Поместите код в
head
и выполняется как первый встроенный скрипт. Таким образом, он будет слушать ошибки, произошедшие после сценария.Используйте захват событий, чтобы поймать ошибки, особенно для тех событий, которые не всплывают.
Используйте делегирование событий, которое позволяет избежать привязки событий на каждом изображении.
Дай ошибку
img
элемент атрибута после предоставления имbackup.png
чтобы избежать исчезновенияbackup.png
и последующий бесконечный цикл, как показано ниже:
img error-> backup.png-> error-> backup.png-> error->,,,,,
Я не уверен, что есть лучший способ, но я могу придумать, как его получить - вы можете Ajax опубликовать URL-адрес img и проанализировать ответ, чтобы увидеть, действительно ли изображение вернулось. Если это вернулось как 404 или что-то, тогда поменяйте img. Хотя я ожидаю, что это будет довольно медленно.
Если изображение не может быть загружено (например, потому что его нет в указанном URL-адресе), URL-адрес изображения изменится на стандартный,
Подробнее о .error()
$('img').on('error', function (e) {
$(this).attr('src', 'broken.png');
});
У меня та же проблема. Этот код хорошо работает в моем случае.
// Replace broken images by a default img
$('img').each(function(){
if($(this).attr('src') === ''){
this.src = '/default_feature_image.png';
}
});