jQuery/JavaScript替换破碎的图像

我有一个网页,里面有很多图片。有时映像不可用,因此在客户机的浏览器中显示一个损坏的映像。

我如何使用jQuery来获取图像集,过滤它到破碎的图像,然后替换src?


—我本以为用jQuery会更容易做到这一点,但事实证明使用纯JavaScript解决方案更容易,也就是Prestaul提供的解决方案。

316032 次浏览

使用JavaScript处理图像的onError事件来重新分配它的源:

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';" />

下面的兼容性表列出了支持错误功能的浏览器:

http://www.quirksmode.org/dom/events/error.html

我相信这就是你想要的:jQuery。预加载

下面是演示中的示例代码,你指定加载和未找到的图像,你就全部设置好了:

jQuery('#images img').preload({
placeholder:'placeholder.jpg',
notFound:'notfound.jpg'
});

我不确定是否有更好的方法,但我可以想到一个hack来获得它-你可以Ajax post到img URL,并解析响应,看看图像是否真的回来了。如果返回404或其他错误,则更换img。不过我估计过程会很缓慢。

这里有一个独立的解决方案:

$(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';
}
});
});

我使用内置的error处理程序:

$("img").error(function () {
$(this).unbind("error").attr("src", "broken.gif");
});

error()方法在jquery 1.8及更高版本中已弃用。相反,你应该使用.on("error"):

$("img").on("error", function () {
$(this).attr("src", "broken.gif");
});
$(window).bind('load', function() {
$('img').each(function() {
if( (typeof this.naturalWidth != "undefined" && this.naturalWidth == 0)
||  this.readyState == 'uninitialized'                                  ) {
$(this).attr('src', 'missing.jpg');
}
});
});

来源:# EYZ0

我找不到适合我需要的脚本,所以我做了一个递归函数来检查损坏的图像,并尝试每四秒重新加载它们,直到它们修复。

我将它限制为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);
});

更好的呼叫使用

jQuery(window).load(function(){
$.imgReload();
});

因为使用document.ready并不一定意味着加载图像,只加载HTML。因此,不需要延迟调用。

如果有人像我一样,试图将error事件附加到动态HTML img标记,我想指出的是,有一个陷阱:

显然,在大多数浏览器中img错误事件不冒泡,与标准所说的相反。

所以,像下面这样的东西将不工作:

$(document).on('error', 'img', function () { ... })

希望这对其他人有所帮助。我希望我能在这个帖子里看到这个。但是,我没有。我把它加起来

(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');

http://jsfiddle.net/ARTsinn/Cu4Zn/

# EYZ0变体:

我这样做是为了修复Turbolinks的一个问题,该问题有时会导致.error()方法在Firefox中被引发,即使图像确实存在。

$("img").error ->
e = $(@).get 0
$(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)

我用这两个简单的函数解决了这个问题:

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');
}
});
}

这是一个快速和肮脏的方法来替换所有破碎的图像,没有必要改变HTML代码;)

< a href = " https://codepen。io/ASHFAQAHMED/pen/RYxyjm" rel="nofollow noreferrer">代码依赖示例 . io/ASHFAQAHMED/pen/RYxyjm" rel="nofollow noreferrer">代码依赖示例

    $("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);">

多年来,这一直困扰着我。我的CSS修复设置了一个背景图像在img。当动态图像src没有加载到前景时,一个占位符在img的bg上可见。如果你的图像有一个默认大小(例如heightmin-heightwidth和/或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;
animation: fadein 1s;
}


@keyframes fadein {
0%   { opacity: 0.0; }
50%  { opacity: 0.5; }
100% { opacity: 1.0; }
}

.dynamicContainer img {
background: url('https://picsum.photos/id/237/200');
background-size: contain;
animation: fadein 1s;
}


@keyframes fadein {
0% {
opacity: 0.0;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1.0;
}
}


img {
/* must define dimensions */
width: 200px;
height: 200px;
min-width: 200px;
min-height: 200px;
/* hides broken text */
color: transparent;
/* optional css below here */
display: block;
border: .2em solid black;
border-radius: 1em;
margin: 1em;
}
<div class="dynamicContainer">
<img src="https://picsum.photos/200" alt="Found image" />
<img src="https://picsumx.photos/200" alt="Not found image" />
</div>

通过使用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;
}

这是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] );
}

< a href = " http://codepen.io/elstermann/pen/giEvC?编辑=001" rel="nofollow noreferrer">CODEPEN:

如果你已经插入了imginnerHTML,比如:$("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)">

为什么需要# eyz0 ?因为通过innerHTML中的脚本标记注入DOM的脚本在注入时不会运行,所以必须显式。

你可以使用GitHub自己的fetch:

< p >前端:# EYZ0 < br > 或者在后端,一个Node.js版本:https://github.com/bitinn/node-fetch

fetch(url)
.then(function(res) {
if (res.status == '200') {
return image;
} else {
return placeholder;
}
}

编辑:这个方法将取代XHR,据说已经在Chrome。对于将来阅读这篇文章的人来说,您可能不需要包含上述库。

我在看这是另一个SO帖子时发现了这篇文章。下面是我在那里给出的答案的副本。

我知道这是一个老帖子,但React已经变得流行起来,也许使用React的人会来这里寻找同样问题的答案。

所以,如果你正在使用React,你可以像下面这样做,这是由React团队在这里的Ben Alpert提供的原始答案

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} />;
);
}
我创建了一个小提琴来替换使用“onerror”事件损坏的图像。 这可能对你有帮助。< / p >
    //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))
})

当OP正在寻找替换SRC时,我相信许多人遇到这个问题可能只希望隐藏损坏的图像,在这种情况下,这个简单的解决方案对我来说非常有用。

使用内联JavaScript:

<img src="img.jpg" onerror="this.style.display='none';" />

Using External JavaScript:

var images = document.querySelectorAll('img');


for (var i = 0; i < images.length; i++) {
images[i].onerror = function() {
this.style.display='none';
}
}
<img src='img.jpg' />

Using Modern External JavaScript:

document.querySelectorAll('img').forEach((img) => {
img.onerror = function() {
this.style.display = 'none';
}
});
<img src='img.jpg' />

See browser support for NodeList.forEach and arrow functions.

下面是一个使用JQuery包装的HTML5 Image对象的示例。为主图像URL调用load函数,如果加载导致错误,则用备份URL替换图像的src属性。

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>
< p >纯JS。 我的任务是:如果图像'bl-once.png'是空的->插入第一个(没有404状态)图像从数组列表(在当前目录):

.png

<img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)">

Maybe it needs to be improved, but:

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'从当前目录。

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" );

reference

我也有同样的问题。这个代码在我的案子上很有效。

// Replace broken images by a default img
$('img').each(function(){
if($(this).attr('src') === ''){
this.src = '/default_feature_image.png';
}
});

有时使用error事件是不可行的,例如,因为你试图在一个已经加载的页面上做一些事情,比如当你通过控制台、bookmarklet或异步加载的脚本运行代码时。在这种情况下,检查img.naturalWidthimg.naturalHeight是否为0似乎可以解决问题。

例如,这里有一个片段,从控制台重新加载所有损坏的图像:

$$("img").forEach(img => {
if (!img.naturalWidth && !img.naturalHeight) {
img.src = img.src;
}
}

如果图像无法加载(例如,因为它不在提供的URL中),图像URL将被更改为默认值,

有关. error ()的更多信息

$('img').on('error', function (e) {
$(this).attr('src', 'broken.png');
});

我认为即使在备份映像加载失败时,我在windowerror上也有一种更优雅的事件委托和事件捕获方法。

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">

重点是:

  1. 将代码放在head中,并作为第一个内联脚本执行。因此,它将侦听脚本执行后发生的错误。

  2. 使用事件捕获来捕获错误,特别是那些没有冒泡的事件。

  3. 使用事件委托,避免在每个图像上绑定事件。

  4. 在给错误img元素一个backup.png之后给它一个属性,以避免backup.png的消失和随后的无限循环,如下所示:

img错误- - - - - - > backup.png - >错误- > backup.png - >错误- >…

我发现这是最好的工作方式,如果任何图像第一次加载失败,它将完全从DOM中删除。执行console.clear()使控制台窗口保持干净,因为404错误不能被try/catch块忽略。

$('img').one('error', function(err) {
// console.log(JSON.stringify(err, null, 4))
$(this).remove()
console.clear()
})

我使用惰性加载,必须这样做,以使它正常工作:

lazyload();


var errorURL = "https://example.com/thisimageexist.png";


$(document).ready(function () {
$('[data-src]').on("error", function () {
$(this).attr('src', errorURL);
});
});

# EYZ0:

<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;
}}
/>