代码之家  ›  专栏  ›  技术社区  ›  Dan Lord

jquery/javascript替换损坏的图像

  •  506
  • Dan Lord  · 技术社区  · 18 年前

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

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


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

    30 回复  |  直到 18 年前
        1
  •  695
  •   Ry- Vincenzo Alcamo    13 年前

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

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

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

        2
  •  189
  •   Chad    7 年前

    我用的是内置的 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");
    });
    
        3
  •  112
  •   Mohd Abdul Mujib    10 年前

    如果像我这样的人试图 error 动态HTML事件 img tag,我想指出的是,这里有一个要点:

    显然 IMG 错误事件 don't bubble 在大多数浏览器中,与 standard 说。

    所以,像下面这样 不工作 :

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

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

        4
  •  55
  •   Devon    18 年前

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

    $(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
  •  32
  •   Nick Craver    18 年前

    我相信这就是你想要的: jQuery.Preload

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

    $('#images img').preload({
        placeholder:'placeholder.jpg',
        notFound:'notfound.jpg'
    });
    
        6
  •  23
  •   XP84    13 年前
    $(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

        7
  •  10
  •   Community Mohan Dere    9 年前

    当操作试图替换SRC时,我相信很多人碰到这个问题可能只希望隐藏损坏的图像,在这种情况下 this simple solution 对我来说很好:

    <img src="someimage.jpg" onerror="this.style.display='none';" />
    
        8
  •  10
  •   Ashfaque Ali Solangi    8 年前

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

    codepen example

        $("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
  •  8
  •   Phil LaNasa    12 年前

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

    <img ...  onerror="this.parentNode.removeChild(this);">
    
        10
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

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

    我将它限制为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);
    });
    
        11
  •  5
  •   Barry    10 年前

    您可以使用github自己的fetch:

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

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

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

        12
  •  5
  •   Axel    9 年前

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

    CODEPEN:

        13
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    更好的呼叫使用

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

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

        14
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    CoffeeScript 变体:

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

    $("img").error ->
      e = $(@).get 0
      $(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)
    
        15
  •  4
  •   Community Mohan Dere    9 年前

    通过使用 Prestaul's answer ,我添加了一些检查,我更喜欢使用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;
    }
    
        16
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    如果您插入了 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中 内层HTML 不会在注入时运行,因此必须明确。

        17
  •  4
  •   Community Mohan Dere    9 年前

    我在看的时候发现了这个帖子 this other SO post . 下面是我在那里给出的答案的副本。

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

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

    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} />;
        );
    }
    
        18
  •  4
  •   Rohith K P    10 年前

    我创造了一个 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))
        })
    
        19
  •  4
  •   Kurt Hartmann    9 年前

    下面是一个使用jquery包装的html5图像对象的示例。调用主图像URL的加载函数,如果该加载导致错误,请用备份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>
    
        20
  •  4
  •   Dima Dorogonov    9 年前

    纯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'。

        21
  •  3
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

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

        22
  •  3
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

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

    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');
            }
        });
    }
    
        23
  •  3
  •   Nabi K.A.Z.    9 年前

    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

        24
  •  2
  •   yckart Matthew Crumley    13 年前
    ;(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/

        25
  •  2
  •   Dylan Valade Ajeesh    12 年前

    多年来这一直让我很沮丧。我的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; }
    }
    
        26
  •  2
  •   Casper    8 年前

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

    更多关于 .error()

    $('img').on('error', function (e) {
      $(this).attr('src', 'broken.png');
    });
        27
  •  2
  •   xianshenglu    8 年前

    我认为我有一种更优雅的方式来处理事件委托和事件捕获 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">

    重点是:

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

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

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

    4. 给出错误 img 元素给它们一个属性 backup.png 为了避免 PNG 以及随后的无限循环,如下所示:

    img错误->backup.png->错误->backup.png->错误->、、、,

        28
  •  1
  •   Dale Nguyen    8 年前

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

    // Replace broken images by a default img
    $('img').each(function(){
        if($(this).attr('src') === ''){
          this.src = '/default_feature_image.png';
        }
    });
    
        29
  •  1
  •   Lea Verou    8 年前

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

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

    $$("img").forEach(img => {
      if (!img.naturalWidth && !img.naturalHeight) {
        img.src = img.src;
      }
    }
    
        30
  •  -1
  •   buycanna.io    7 年前

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

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