jQuery/JavaScript 替换损坏的图像

Posted

技术标签:

【中文标题】jQuery/JavaScript 替换损坏的图像【英文标题】:jQuery/JavaScript to replace broken images 【发布时间】:2010-09-10 16:48:00 【问题描述】:

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

如何使用 jQuery 获取图像集,将其过滤为损坏的图像,然后替换 src?


--我认为使用 jQuery 会更容易做到这一点,但结果证明只使用纯 javascript 解决方案要容易得多,即 Prestaul 提供的解决方案。

【问题讨论】:

【参考方案1】:

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

【讨论】:

你可能想在 before 设置 src 之前清除 onerror。否则,如果 noimage.gif 也丢失,您最终可能会出现“堆栈溢出”。 我认为并希望我们正在摆脱 javascript 事件的内联属性... redsquare...当您明智地控制它们时,它们是完全可以理解的,当您希望标记反映实际发生的情况时,它们甚至会很有用。 好点 NickC,关于显示正在发生的事情的标记,当我看到它时我只是畏缩:P @redsquare,我完全同意,但这是一个独特的案例。内联是唯一可以附加侦听器的地方,绝对可以肯定在附加侦听器之前事件不会触发。如果您在文档末尾执行此操作或等待 DOM 加载,您可能会错过某些图像上的错误事件。在事件触发后附加错误处理程序对您没有好处。【参考方案2】:

我使用内置的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");
);

【讨论】:

如果您使用这种技术,您可以使用“one”方法来避免需要取消绑定事件: $('img').one('error', function() this.src = 'broken.gif'; );【参考方案3】:

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

显然img 错误事件don't bubble 在大多数浏览器中,与standard 所说的相反。

因此,类似以下的内容将不起作用

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

希望这对其他人有帮助。我希望我在这个线程中看到了这个。但是,我没有。所以,我添加它

【讨论】:

没用。我动态加载一个死图像并将其附加到 dom 中,并且没有触发任何“错误”事件。【参考方案4】:

这是一个独立的解决方案:

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

【讨论】:

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

我相信这就是你所追求的:jQuery.Preload

这是演示中的示例代码,您指定加载和未找到的图像,一切就绪:

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

【讨论】:

是的...这在第一行的答案中链接。【参考方案6】:
$(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】:

当 OP 正在寻找替换 SRC 时,我敢肯定很多遇到这个问题的人可能只想隐藏损坏的图像,在这种情况下 this simple solution 对我来说非常有用。

使用内联 JavaScript:

&lt;img src="img.jpg" onerror="this.style.display='none';" /&gt;

使用外部 JavaScript:

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

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

使用现代外部 JavaScript:

document.querySelectorAll('img').forEach((img) => 
  img.onerror = function() 
    this.style.display = 'none';
  
);
&lt;img src='img.jpg' /&gt;

查看浏览器对NodeList.forEach 和arrow functions 的支持。

【讨论】:

【参考方案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】:

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

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

【讨论】:

【参考方案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】:

您可以为此使用 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】:

这是 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】:

更好的调用使用

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

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

【讨论】:

【参考方案14】:

CoffeeScript 变种:

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

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

【讨论】:

【参考方案15】:

通过使用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】:

如果您在innerHTML 中插入了img,例如:$("div").innerHTML = &lt;img src="wrong-uri"&gt;,如果它失败,您可以加载另一个图像,例如:

<script>
    function imgError(img) 
        img.error="";
        img.src="valid-uri";
    
</script>

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

为什么需要javascript: _?因为通过innerHTML 中的脚本标签注入到 DOM 中的脚本在注入时不会运行,因此您必须明确。

【讨论】:

【参考方案17】:

我在查看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】:

我创建了一个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】:

这是一个使用 JQuery 包装的 HTML5 Image 对象的示例。调用主图像 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>

【讨论】:

【参考方案20】:

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

&lt;img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)"&gt;

也许需要改进,但是:

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】:
(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/

【讨论】:

【参考方案22】:

多年来,这一直让我感到沮丧。我的 CSS 修复在 img 上设置了背景图像。当动态图像src 未加载到前台时,img 的背景上会显示一个占位符。如果您的图像具有默认大小(例如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"  />
  <img src="https://picsumx.photos/200"  />
</div>

【讨论】:

【参考方案23】:

我不确定是否有更好的方法,但我可以想出一个技巧来获得它 - 你可以将 Ajax 发布到 img URL,然后解析响应以查看图像是否真的返回了。如果它以 404 或其他形式返回,则换掉 img。虽然我预计这会很慢。

【讨论】:

【参考方案24】:

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

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

【讨论】:

【参考方案25】:

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

【讨论】:

【参考方案26】:

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

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

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

【讨论】:

【参考方案27】:

我认为我有一种更优雅的方式来处理 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" >
<img id="img" src="error2.png" >
<img id="img" src="https://i.stack.imgur.com/ZXCE2.jpg" >

重点是:

    将代码放在head 中并作为第一个内联脚本执行。所以,它会监听脚本之后发生的错误。

    使用事件捕获来捕获错误,尤其是那些没有冒泡的事件。

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

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

img error->backup.png->error->backup.png->error->,,,,,

【讨论】:

这是迄今为止最好的答案。我唯一建议的是使用let isImgErrorHandled = target.src === 'backup.png';,因为它可以简化一点。 @Sabo,有一点问题,因为 src 路径可能不等于我分配的路径。比如target.src='backup.png',但是下次console.log(target.src)可能就不是backup.png【参考方案28】:

对于 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;
    
 />

【讨论】:

【参考方案29】:

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

更多关于.error()

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

【讨论】:

【参考方案30】:

我遇到了同样的问题。这段代码适用于我的情况。

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

【讨论】:

以上是关于jQuery/JavaScript 替换损坏的图像的主要内容,如果未能解决你的问题,请参考以下文章

自动替换损坏的图像

如何从第三方应用程序替换评论部分中的图像

使用正则表达式(regex)替换jQuery / JavaScript中的选定文本

如何使用 Jquery/Javascript 将我的一个文件夹中的所有图像加载到我的网页中

如何使用 jquery/javascript 捕获页面上的所有回发?

Excel图像损坏,没有被指定在windows上运行,或者包含错误怎么办?