【问题标题】:Check if an image is loaded (no errors) with jQuery检查是否使用 jQuery 加载了图像(没有错误)
【发布时间】:2017-04-01 07:18:11
【问题描述】:

我正在使用带有 jQ​​uery 库的 JavaScript 来处理包含在无序列表中的图像缩略图。加载图像时,它会做一件事,当发生错误时,它会做另一件事。我使用 jQuery load()error() 方法作为事件。 在这些事件之后,我检查 .complete 的图像 DOM 元素,以确保在 jQuery 注册事件之前图像尚未加载。

它可以正常工作,除非在 jQuery 注册事件之前发生错误。 我能想到的唯一解决方案是使用 img onerror 属性在全局某处存储“标志”(或者在它自己的节点上)说它失败了,所以jQuery可以在检查.complete时检查那个“存储/节点”。

谁有更好的解决方案?

编辑:粗体的要点并在下面添加了额外的细节: 在图像上添加加载和错误事件后,我正在检查图像是否完整(也称为加载)。这样,如果图像是在事件注册之前加载的,我仍然会知道。如果图像在事件之后没有加载,那么事件会在它加载时处理它。这样做的问题是,我可以轻松检查是否已经加载了图像,但 我无法判断是否发生了错误。

【问题讨论】:

标签: javascript jquery image dom jquery-events


【解决方案1】:

按顺序检查completenaturalWidth 属性。

https://stereochro.me/ideas/detecting-broken-images-js

function IsImageOk(img) {
    // During the onload event, IE correctly identifies any images that
    // weren’t downloaded as not complete. Others should too. Gecko-based
    // browsers act like NS4 in that they report this incorrectly.
    if (!img.complete) {
        return false;
    }

    // However, they do have two very useful properties: naturalWidth and
    // naturalHeight. These give the true size of the image. If it failed
    // to load, either of these should be zero.
    if (img.naturalWidth === 0) {
        return false;
    }

    // No other way of checking: assume it’s ok.
    return true;
}

【讨论】:

  • 有趣的是,我之前在看那个帖子,我没有意识到他们在做! IE 完整,因为 naturalWidth 未在 IE 中定义。现在去检查一下。
  • 显然,这只能在第一次可靠地工作。如果您随后更改图像的 src,至少 safari mobile 将继续报告 naturalWidth 和 complete 的第一个值。
  • return img.complete && typeof img.naturalWidth != 'undefined' && img.naturalWidth != 0;
  • @vsync 您可能希望将其用作一次性检查,如果图像尚未加载,请设置“加载”事件处理程序。应该没有必要通过多次运行此检查来敲击 CPU。
  • 对于那些好奇的人,这几乎正是下面链接的 imagesLoaded 库所做的。所以,对于一次性使用,去吧:github.com/desandro/imagesloaded/blob/master/…
【解决方案2】:

另一个选项是通过在内存中创建图像元素并将其src 属性设置为原始图像的原始src 属性来触发onload 和/或onerror 事件。这是我的意思的一个例子:

$("<img/>")
    .on('load', function() { console.log("image loaded correctly"); })
    .on('error', function() { console.log("error loading image"); })
    .attr("src", $(originalImage).attr("src"))
;

希望这会有所帮助!

【讨论】:

  • 似乎没有像我希望的那样工作。在谷歌浏览器中,当图像已经在缓存中时,它似乎有问题。它不会触发 load() 方法。 :(
  • Ugg,你是对的。 Chrome 绝对是开发时最烦人的浏览器。在明亮的情况下,我想我可能找到了解决方法:将图像源设置为“”,然后返回原始源。我会更新我的答案。
  • 您应该将.attr放在 .load.error 行之后。否则,您可能会在添加这些回调之前加载图像(或遇到错误),并且不会调用它们。
  • @Xavi Chrome 并不是最讨厌开发的浏览器,请尝试为 Internet Explorer 7 或更低版本开发。除了在图像加载中添加 $_GET 参数外,每次都会加载新图像,就像 Gromix 建议的那样。
  • .load().error() 方法令人困惑,现已弃用,使用 .on() 并使用 loaderror 作为事件。
【解决方案3】:

据我了解, .complete 属性是非标准的。它可能不是通用的......我注意到它在 Firefox 和 IE 中的工作方式似乎不同。我在 javascript 中加载了一些图像,然后检查是否完成。在 Firefox 中,这似乎工作得很好。在 IE 中,这不是因为图像似乎正在另一个线程上加载。仅当我在分配给 image.src 和检查 image.complete 属性之间延迟时,它才有效。

使用 image.onload 和 image.onerror 对我也不起作用,因为我需要传递一个参数来知道调用该函数时我正在谈论的图像。任何这样做的方式似乎都失败了,因为它实际上似乎传递了相同的函数,而不是同一函数的不同实例。因此,我传递给它以识别图像的值总是最终成为循环中的最后一个值。我想不出任何办法来解决这个问题。

在 Safari 和 Chrome 上,即使错误控制台显示该图像的 404,我也看到 image.complete 为 true 和 naturalWidth 设置...我故意删除了该图像以进行测试。但上述方法适用于 Firefox 和 IE。

【讨论】:

  • 嗯,这很有趣。介意发布一个代码示例,以便我尝试一些事情吗?
【解决方案4】:

这就是我使用上述方法的组合使其跨浏览器工作的方式(我还需要将图像动态插入到 dom 中):

$('#domTarget').html('<img src="" />');

var url = '/some/image/path.png';

$('#domTarget img').load(function(){}).attr('src', url).error(function() {
    if ( isIE ) {
       var thisImg = this;
       setTimeout(function() {
          if ( ! thisImg.complete ) {
             $(thisImg).attr('src', '/web/css/img/picture-broken-url.png');
          }
       },250);
    } else {
       $(this).attr('src', '/web/css/img/picture-broken-url.png');
    }
});

注意:您需要为 isIE 变量提供一个有效的布尔状态。

【讨论】:

    【解决方案5】:

    我尝试了很多不同的方法,这是唯一适合我的方法

    //check all images on the page
    $('img').each(function(){
        var img = new Image();
        img.onload = function() {
            console.log($(this).attr('src') + ' - done!');
        }
        img.src = $(this).attr('src');
    });
    

    您还可以添加一个回调函数,在所有图像都加载到 DOM 并准备就绪后触发。这也适用于动态添加的图像。 http://jsfiddle.net/kalmarsh80/nrAPk/

    【讨论】:

    • 我已经测试了上面有趣的读取,它们在少数常见浏览器上的缓存/非缓存测试之间失败了。这个答案与另一个答案相似,但这是我刚刚实施和测试的答案,我可以确认它适用于:EdgeWin10、IE11Win8.1、Win7IE10、Win7IE9、iOS 10.2 Chrome、iOS 10.2 Safari、mac os 10.12 Chrome、mac os 10.12 Safari、mac os 10.12 Firefox、Google Pixel 7.1、三星 S5 Android 4.4。不要忘记使用 addEventListener/removeEventListener :D
    • 请注意,这在技术上会加载图像的 另一个 副本,并使用该代理的加载事件作为图像的事件。如果 HTTP 标头不允许共享缓存的结果,这显然无法将原始图像与相同的 URL 匹配!
    【解决方案6】:

    实时网络检测器 - 无需刷新页面即可检查网络状态: (它不是 jquery,而是经过测试,并且 100% 有效:(在 Firefox v25.0 上测试))

    代码:

    <script>
     function ImgLoad(myobj){
       var randomNum = Math.round(Math.random() * 10000);
       var oImg=new Image;
       oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
       oImg.onload=function(){alert('Image succesfully loaded!')}
       oImg.onerror=function(){alert('No network connection or image is not available.')}
    }
    window.onload=ImgLoad();
    </script>
    
    <button id="reloadbtn" onclick="ImgLoad();">Again!</button>
    

    如果连接丢失,只需按“再次”按钮。

    更新 1: 不刷新页面自动检测:

    <script>
         function ImgLoad(myobj){
           var randomNum = Math.round(Math.random() * 10000);
           var oImg=new Image;
           oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
           oImg.onload=function(){networkstatus_div.innerHTML="";}
           oImg.onerror=function(){networkstatus_div.innerHTML="Service is not available. Please check your Internet connection!";}
    }
    
    networkchecker = window.setInterval(function(){window.onload=ImgLoad()},1000);
    </script>
    
    <div id="networkstatus_div"></div>
    

    【讨论】:

    • 100%!如果您的图片链接被代理/防火墙阻止或图片服务器没有响应怎么办?你仍然有网络工作:)
    • 这将再次从服务器加载每个图像,从而破坏缓存(故意)。因此,仅出于检查目的,您(至少)将所有图像的带宽加倍。此外,它只检查图像是否存在于服务器上,而不是它是否被加载到某个特定位置。也无法知道每个图像何时加载。
    【解决方案7】:

    【讨论】:

    • 这对我来说非常有效。函数 checkImages(imgs) { $(imgs).each(function() { $(imgs).imagesLoaded() .progress(function(instance, image) { if(image.isLoaded == false) { console.log(image .img.src + ' 找不到。'); image.img.src = "/templates/img/no-image.jpg"; } }); }); }
    • 它似乎有很多未解决的问题,其中主要错误,而开发人员似乎并没有做太多的事情来解决它们。截至目前,这在生产环境中完全无法使用。
    • @vsync 你读过一些未解决的问题吗?他几乎对所有这些都做出了回应,而且大多数似乎都是其他人很少遇到的不可重现的边缘情况。我在生产中从来没有遇到过问题。
    • 是的,我自己使用它,有时它不起作用,所以我使用 setTimeout 来覆盖它失败的情况
    • 为什么要使用 imagesLoaded 插件有充分的理由:complete 属性似乎没有得到明确支持:无法找到有关浏览器支持的可靠信息来源。 complete 属性似乎也没有明确的规范:HTML5 规范是唯一提及它的规范,并且在撰写本文时它仍处于草稿版本中。如果你使用naturalWidth & naturalHeight 只支持 IE9+,所以如果你用它来判断图像是否被加载,你需要一些“聪明”的技巧让它在旧浏览器上工作,你必须检查交叉-浏览器行为一致
    【解决方案8】:

    阅读此页面上有趣的解决方案后,我创建了一个易于使用的解决方案,该解决方案深受 SLaks 和 Noyo 的帖子的影响,该解决方案似乎适用于 Chrome、IE、Firefox、 Safari 和 Opera(都在 Windows 上)。此外,它还可以在我使用的 iPhone/iPad 模拟器上运行。

    此解决方案与 SLaks 和 Noyo 的帖子之间的一个主要区别是此解决方案主要检查 naturalWidth 和 naturalHeight 属性。我发现在当前的浏览器版本中,这两个属性似乎提供了最有用和最一致的结果。

    当图像完全加载并成功时,此代码返回 TRUE。当图像尚未完全加载或加载失败时,它返回 FALSE。

    您需要注意的一件事是,如果图像是 0x0 像素图像,此函数也将返回 FALSE。但是这些图像非常少见,我想不出一个非常有用的情况来检查是否已加载 0x0 像素图像:)

    首先我们将一个名为“isLoaded”的新函数附加到 HTMLImageElement 原型中,以便可以在任何图像元素上使用该函数。

    HTMLImageElement.prototype.isLoaded = function() {
    
        // See if "naturalWidth" and "naturalHeight" properties are available.
        if (typeof this.naturalWidth == 'number' && typeof this.naturalHeight == 'number')
            return !(this.naturalWidth == 0 && this.naturalHeight == 0);
    
        // See if "complete" property is available.
        else if (typeof this.complete == 'boolean')
            return this.complete;
    
        // Fallback behavior: return TRUE.
        else
            return true;
    
    };
    

    那么,每当我们需要检查图片的加载状态时,我们只需调用“isLoaded”函数即可。

    if (someImgElement.isLoaded()) {
        // YAY! The image loaded
    }
    else {
        // Image has not loaded yet
    }
    

    根据 giorgian 对 SLaks 和 Noyo 帖子的评论,如果您打算更改 SRC 属性,此解决方案可能只能用作 Safari Mobile 的一次性检查。但是您可以通过创建具有新 SRC 属性的图像元素来解决此问题,而不是更改现有图像元素的 SRC 属性。

    【讨论】:

    • 请注意,有些浏览器会为所有 SVG 图像返回 naturalWidth==0 以表明这些图像可以缩放。你应该总是更喜欢先检查.complete,只有在无法使用时才诉诸黑客攻击。
    【解决方案9】:

    使用此JavaScript 代码,您可以检查图像是否成功加载。

    document.onready = function(e) {
            var imageobj = new Image();
            imageobj.src = document.getElementById('img-id').src;
            if(!imageobj.complete){ 
                alert(imageobj.src+"  -  Not Found");
            }
    }
    

    试试这个

    【讨论】:

      【解决方案10】:

      根据我对the W3C HTML Specification for the img element 的理解,您应该能够使用completenaturalHeight 属性的组合来执行此操作,如下所示:

      function imgLoaded(imgElement) {
        return imgElement.complete && imgElement.naturalHeight !== 0;
      }
      

      来自complete 属性的规范:

      如果满足以下任一条件,则 IDL 属性完成必须返回 true 条件为真:

      • src 属性被省略。
      • 获取资源后网络任务源排队的最终任务已排队。
      • img 元素完全可用。
      • img 元素已损坏。

      否则,该属性必须返回 false。

      所以本质上,complete 如果图像已完成加载或加载失败,则返回 true。由于我们只需要成功加载图像的情况,我们还需要检查 nauturalHeight 属性:

      IDL 属性 naturalWidthnaturalHeight 必须返回 图像的固有宽度和高度,以 CSS 像素为单位,如果图像 可用,否则为 0。

      available 的定义如下:

      img 总是处于以下状态之一:

      • 不可用 - 用户代理尚未获得任何图像数据。
      • 部分可用 - 用户代理已获取部分图像数据。
      • 完全可用 - 用户代理已获取所有图像数据,并且至少图像尺寸可用。
      • Broken - 用户代理已经获得了它所能获得的所有图像数据,但它甚至无法将图像解码到足以获得图像的程度 尺寸(例如,图像已损坏,或格式不正确 支持,否则无法获取数据)。

      当一个 img 元素处于部分可用状态或 完全可用的状态,称为可用。

      所以如果图像“损坏”(加载失败),那么它将处于损坏状态,而不是可用状态,因此naturalHeight 将为 0。

      因此,检查imgElement.complete &amp;&amp; imgElement.naturalHeight !== 0 应该告诉我们图像是否已成功加载。

      您可以在the W3C HTML Specification for the img elementon MDN 中了解更多信息。

      【讨论】:

      【解决方案11】:

      从页面上的图像元素中检索信息
      在 Chrome 和 Firefox 上测试工作
      工作jsFiddle(打开控制台查看结果)

      $('img').each(function(){ // selecting all image element on the page
      
          var img = new Image($(this)); // creating image element
      
          img.onload = function() { // trigger if the image was loaded
              console.log($(this).attr('src') + ' - done!');
          }
      
          img.onerror = function() { // trigger if the image wasn't loaded
              console.log($(this).attr('src') + ' - error!');
          }
      
          img.onAbort = function() { // trigger if the image load was abort
              console.log($(this).attr('src') + ' - abort!');
          }
      
          img.src = $(this).attr('src'); // pass src to image object
      
          // log image attributes
          console.log(img.src);
          console.log(img.width);
          console.log(img.height);
          console.log(img.complete);
      
      });
      

      注意:我使用jQuery,我认为这可以在完整的javascript上实现

      我在这里找到了很好的信息OpenClassRoom --> 这是一个法语论坛

      【讨论】:

      • 请注意,此版本还会为每个图像加载 extra 副本,如果缓存不允许使用相同的副本,您只需将下载大小加倍并获取错误的事件时间。
      【解决方案12】:

      我在完整加载图像和 EventListener 时遇到了很多问题。

      无论我怎么尝试,结果都不可靠。

      但后来我找到了解决方案。从技术上讲,这不是一个好的,但现在我从来没有遇到过图像加载失败的情况。

      我做了什么:

                          document.getElementById(currentImgID).addEventListener("load", loadListener1);
                          document.getElementById(currentImgID).addEventListener("load", loadListener2);
      
                      function loadListener1()
                          {
                          // Load again
                          }
      
                      function loadListener2()
                      {
                          var btn = document.getElementById("addForm_WithImage"); btn.disabled = false;
                          alert("Image loaded");
                      }
      

      我不是一次加载图像,而是在第一次之后直接加载第二次,并且都通过事件处理程序运行。

      我所有的头痛都消失了!


      顺便说一句: 来自stackoverflow的你们已经帮助了我超过一百次。非常感谢!

      【讨论】:

        【解决方案13】:

        这段代码帮助我修复了浏览器缓存问题:

        $("#my_image").on('load', function() {
        
            console.log("image loaded correctly"); 
        }).each(function() {
        
             if($(this).prop('complete')) $(this).load();
        });
        

        当浏览器缓存被禁用时,只有这段代码不起作用:

        $("#my_image").on('load', function() {
             console.log("image loaded correctly"); 
        })
        

        要使其正常工作,您必须添加:

        .each(function() {
             if($(this).prop('complete')) $(this).load();
        });
        

        【讨论】:

          【解决方案14】:
          var isImgLoaded = function(imgSelector){
            return $(imgSelector).prop("complete") && $(imgSelector).prop("naturalWidth") !== 0;
          }
          

          // 或作为插件

              $.fn.extend({
                isLoaded: function(){
                  return this.prop("complete") && this.prop("naturalWidth") !== 0;
                }
              })
          
          // $(".myImage").isLoaded() 
          

          【讨论】:

            【解决方案15】:

            这个对我来说很好用:)

            $('.progress-image').each(function(){
                var img = new Image();
                img.onload = function() {
                    let imgSrc = $(this).attr('src');
                    $('.progress-image').each(function(){
                        if($(this).attr('src') == imgSrc){
                            console.log($(this).parent().closest('.real-pack').parent().find('.shimmer').fadeOut())
                        }
                    })
                }
                img.src = $(this).attr('src');
            });
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-12
              • 2014-01-04
              • 1970-01-01
              相关资源
              最近更新 更多