jQuery/JavaScript替换损坏的图片

588

我有一个网页包含多张图片,有时候这些图片不可用,导致在客户端的浏览器上显示损坏的图片。

我该如何使用jQuery获取图像集、筛选损坏的图像并替换其src?


--我原以为使用jQuery会更容易,但事实证明纯JavaScript的解决方案更加简单,即Prestaul提供的方法。

32个回答

819

使用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


142
在设置src之前,您可能希望先清除onerror。否则,如果noimage.gif也丢失,您可能会遇到“堆栈溢出”的问题。 - pcorcoran
49
我原以为并且希望我们正在远离使用内联属性来处理javascript事件... - redsquare
25
当你能够谨慎控制时,红色框线是非常容易理解的,甚至在你想让你的标记反映实际情况时也可以很有用。 - Nicole
2
NickC说得好,标记显示了正在发生的事情,但每次看到它我都会感到不舒服 :P - SSH This
39
@redsquare,我完全同意,但这是一个特殊情况。内联是唯一可以确保事件不会在您附加侦听器之前触发的地方。如果您在文档末尾执行此操作或等待DOM加载,您可能会错过某些图像上的错误事件。在事件触发后再附加错误处理程序对您没有任何好处。 - Prestaul

214

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

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

编辑:JQuery 1.8及以上版本中已废弃error()方法。应使用.on("error")代替:

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

118
如果您使用这种技术,您可以使用“one”方法来避免需要解除绑定事件的需求:$('img').one('error', function() { this.src = 'broken.gif'; }); - Prestaul

136

如果有人像我一样,试图将error事件附加到动态HTML img标签上,我想指出一个问题:

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

因此,以下示例不起作用

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

希望这对其他人有所帮助。我希望我能在这个讨论串中看到这个内容,但是我没有。所以,我将它添加上去。


1
加载死图像并将其动态附加到DOM中,但没有触发“错误”事件。 - vsync

65

以下是独立的解决方案:

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

5
几乎正确...在IE中正确的图像仍将返回 (typeof(this.naturalWidth) == "undefined") == true; - 我将if语句更改为(!this.complete || (!$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0))) - Sugendran

39

我认为这就是你想要的内容:jQuery.Preload

这里是演示中的示例代码,你需要指定加载和未找到图片,然后就可以开始了:

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

17
是的,这个链接在第一行的回答中提到了。 - Nick Craver

31

27

虽然OP想要替换SRC,但我相信很多遇到这个问题的人只希望隐藏破损的图片,在这种情况下,这个简单的解决方案对我非常有效。

使用内联JavaScript:

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

使用外部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' />

使用现代的外部JavaScript:

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

查看NodeList.forEach箭头函数的浏览器支持。


11

这是一个很烂的技巧,但它几乎是可以保证的:

<img onerror="this.parentNode.removeChild(this);">

11

这里有一种快速而简便的方法来替换所有损坏的图像,而且无需更改HTML代码😉

Codepen示例

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

9

我没有找到适合我的需求的脚本,所以我编写了一个递归函数来检查损坏的图像,并尝试在四秒内重新加载它们,直到它们被修复为止。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接