jQuery / JavaScript来替换破碎的图像

jQuery/JavaScript to replace broken images

我有一个网页,上面有一堆图片。有时图像不可用,因此客户机的浏览器中会显示损坏的图像。

如何使用jquery获取图像集,将其过滤为断开的图像,然后替换SRC?


--我原以为用jquery做这件事会更容易些,但事实证明,仅仅使用纯JavaScript解决方案(即Prestaul提供的解决方案)就容易多了。


处理图像的onError事件,使用javascript重新分配其源:

1
2
3
4
5
function imgError(image) {
    image.onerror ="";
    image.src ="/images/noimage.gif";
    return true;
}
1
<img src="image.png" onerror="imgError(this);"/>

或者没有javascript函数:

1
<img src="image.png" onError="this.onerror=null;this.src='/images/noimage.gif';" />

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

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


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

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

编辑:1.8及更高版本中不推荐使用error()方法。相反,您应该使用.on("error")来代替:

1
2
3
$("img").one("error", function () {
  $(this).attr("src","broken.gif");
});


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

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

因此,像下面这样的事情是行不通的:

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

希望这对其他人有帮助。我真希望我能在这条线上看到这个。但是,我没有。所以,我要补充一下


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

1
2
3
4
5
6
7
8
$(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

下面是演示中的示例代码,您指定了加载和未找到的图像,并且已经设置好了:

1
2
3
4
$('#images img').preload({
    placeholder:'placeholder.jpg',
    notFound:'notfound.jpg'
});


1
2
3
4
5
6
7
8
$(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.developeria.com/2009/03/jquery-quickie---break-images.html


虽然OP希望替换SRC,但我相信很多人在回答这个问题时,可能只希望隐藏损坏的图像,在这种情况下,这个简单的解决方案对我很有用:

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


这里有一个快速而肮脏的方法来替换所有损坏的图像,并且不需要更改HTML代码;)

代码笔示例

1
2
3
4
5
6
7
8
9
10
11
12
    $("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"),
            });
        }
  });


这是一种糟糕的技术,但它几乎可以保证:

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


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

我将它限制为10次尝试,就好像它没有被加载一样,那么服务器上的映像可能不存在,函数将进入一个无限循环。不过,我仍在测试。请随意调整:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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自己的fetch:

前端:https://github.com/github/fetch或者对于后端,使用node.js版本:https://github.com/bitin/node-fetch

1
2
3
4
5
6
7
8
fetch(url)
  .then(function(res) {
    if (res.status == '200') {
      return image;
    } else {
      return placeholder;
    }
  }

编辑:这个方法将取代XHR,而且应该已经在Chrome中了。对于将来阅读此内容的任何人,您可能不需要包含上述库。


这是Javascript,应该是跨浏览器兼容的,并且没有难看的标记onerror=""

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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] );
}

代码笔:


更好的呼叫使用

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

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


咖啡描述变体:

我之所以这么做是为了修复turbolinks的一个问题,它有时会导致firefox中出现.error()方法,即使图像确实存在。

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


通过使用Prestaul的答案,我添加了一些检查,我更喜欢使用jquery方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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;
}


如果您已将您的imginnerHTML一起插入,例如:$("div").innerHTML = ,则如果失败,可以加载另一个图像,例如:

1
2
3
4
5
6
7
    function imgError(img) {
        img.error="";
        img.src="valid-uri";
    }


<img src="wrong-uri" onerror="javascript:imgError(this)">

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


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

我知道这是一条古老的线索,但是react已经很流行了,也许,使用react的人会来这里寻找相同问题的答案。

因此,如果您使用react,您可以执行如下操作,这是react团队的Ben Alpert提供的原始答案

1
2
3
4
5
6
7
8
9
10
11
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"事件替换损坏的图像。这可能对你有帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    //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))
    })

下面是一个使用jquery包装的html5图像对象的示例。调用主图像URL的加载函数,如果该加载导致错误,请用备份URL替换图像的src属性。

1
2
3
4
5
6
7
8
9
10
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"/>

    loadImageUseBackupUrlOnError('myImage','primary-image-url','backup-image-url');


纯JS。我的任务是:如果图像"bl once.png"为空,则从数组列表(在当前目录中)插入第一个(状态不是404)图像:

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

也许需要改进,但是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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'。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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');
        }
    });
}


查询1.8

1
2
3
4
5
6
// If missing.png is missing, it is replaced by replacement.png
$("img" )
  .error(function() {
    $( this ).attr("src","replacement.png" );
  })
  .attr("src","missing.png" );

查询3

1
2
3
4
5
6
// If missing.png is missing, it is replaced by replacement.png
$("img" )
  .on("error", function() {
    $( this ).attr("src","replacement.png" );
  })
  .attr("src","missing.png" );

参考


我不确定是否有更好的方法,但我可以想到一个黑客来获得它-你可以Ajax发布到img的URL,并解析响应以查看图像是否真的回来了。如果它以404或其他形式返回,那么换掉IMG。尽管我预计这会很慢。


1
2
3
4
5
6
7
;(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] || ''; });
    });
};

您可以通过$*传递占位符路径并在其中访问失败图像对象的所有属性:

1
$('img').fallback('http://dummyimage.com/$widthx$height&text=$src');

http://jsfiddle.net/artsinn/cu4zn/


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

有关.error()的详细信息

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


我认为,即使在备份映像加载失败的情况下,在windowerror上,我有一种更优雅的方式来进行事件委派和事件捕获。

1
2
3
4
img {
  width: 100px;
  height: 100px;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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!');
      }
    }
  }

<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中,作为第一个内联脚本执行。因此,它将监听脚本之后发生的错误。

  • 使用事件捕获来捕获错误,尤其是对于那些不冒泡的事件。

  • 使用避免在每个映像上绑定事件的事件委托。

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

  • img error->backup.png->error->backup.png->error->


    多年来这一直让我很沮丧。我的CSS修复程序在img上设置背景图像。当动态图像src没有加载到前景时,在img的bg上可以看到一个占位符。如果您的图像具有默认大小(例如,heightmin-heightwidth和/或min-width,则此选项有效。

    你会看到破碎的图像图标,但这是一个改进。成功测试到IE9。iOS Safari和Chrome甚至没有显示损坏的图标。

    1
    2
    3
    4
    .dynamicContainer img {
      background: url('/images/placeholder.png');
      background-size: contain;
    }

    添加一点动画,让src有时间加载,而不会出现背景闪烁。Chrome在背景中淡入淡出,但桌面Safari没有。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    .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; }
    }


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

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

    有时使用error事件是不可行的,例如,因为您试图在已经加载的页面上执行某些操作,例如,通过控制台运行代码、书签或异步加载的脚本。在这种情况下,检查img.naturalWidthimg.naturalHeight是否为0似乎可以做到这一点。

    例如,下面是从控制台重新加载所有损坏图像的片段:

    1
    2
    3
    4
    5
    $$("img").forEach(img => {
      if (!img.naturalWidth && !img.naturalHeight) {
        img.src = img.src;
      }
    }


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

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