【问题标题】:Browser-independent way to detect when image has been loaded检测图像何时加载的独立于浏览器的方法
【发布时间】:2010-10-23 17:15:39
【问题描述】:

在IE中,可以onreadystatechange。有onload,但我读了scary things。 jQuery 用“ready”很好地包装了 DOM 的加载事件。似乎我只是不知道另一个不错的库的图像加载实现。

上下文是我正在动态生成图像(通过服务器回调),下载可能需要一些时间。在我的 IE-only 代码中,我设置了 img 元素的 src,然后当 onreadystatechange 事件以“完成”状态触发时,我将它添加到 DOM,以便用户看到它。

我会很高兴有一个“原生”JavaScript 解决方案,或者一个指向完成这项工作的库的指针。那里有很多图书馆,我敢肯定这是我不知道正确的图书馆的情况。也就是说,我们已经是 jQuery 用户,所以我不急于添加一个非常大的库来获得这个功能。

【问题讨论】:

  • 我不完全明白——你想要一个单一的纯 JS 解决方案来检测图像何时加载,还是你正在寻找 jQuery 的替代库来检测图像何时加载?
  • 我会很高兴。当我在其他地方使用 jQuery 时,我不会放弃它。只是表示我怀疑这是一个我不熟悉的库中很好解决的问题。
  • 别忘了告诉我们你最终做了什么!
  • 看了一圈后,最好的答案似乎是使用imagesLoaded Javascript library,它是:MIT License,在Github上,海量社区,成熟项目(很老,从2010年开始,但仍然活跃) , 7Kb 缩小(轻量级!),并且没有依赖关系。相关stackoverflow.com/questions/1977871/…

标签: javascript dom


【解决方案1】:

如果我在 javascript 中没有记错,图片标签有 onload 和 onerror 事件

这是我为隐藏损坏的图像所做的一段有趣的代码

在样式标签中

img.failed{
   display:none;
}

使用 img onerror 我有一段 javascript 执行 this.className=failed 如果出错,它会隐藏图像

但是我可能误解了你的目标

【讨论】:

  • 虽然少数浏览器支持它,但 W3C 标准不支持“onload”事件,因此并非所有浏览器都需要或必须支持它。
【解决方案2】:

我发现唯一可靠的方法是像这样在客户端完成所有操作...

var img = new Image();
img.onload = function() {
  alert('Done!');
}
img.src = '/images/myImage.jpg';

【讨论】:

  • 虽然少数浏览器支持它,但 W3C 标准不支持“onload”事件,因此并非所有浏览器都需要或必须支持它。
【解决方案3】:

我认为onload 应该可以正常工作。您必须为图像生成标记,还是可以静态添加它们?如果是后者,我建议如下:

<img src="foo.png" class="classNeededToHideImage" onload="makeVisible(this)">

或者,您可以使用 window.onload 使所有图像同时可见 - window.onload 在所有外部资源完成加载后触发。

如果你想动态添加图片,你首先必须等待 DOM 准备好被修改,即使用 jQuery 或为不支持原生的浏览器实现你自己的 DOMContentLoaded hack。

然后,您创建图像对象,分配 onload 侦听器以使它们可见和/或将它们添加到文档中。

更好(但稍微复杂一点)是在脚本执行时立即创建并开始加载图像。在 DOMContentLoaded 上,您必须检查每个图像的 complete 以决定是立即将它们添加到文档中,还是等待图像的 onload 侦听器触发。

【讨论】:

  • 虽然少数浏览器支持它,但 W3C 标准不支持“onload”事件,因此并非所有浏览器都需要或必须支持它。
  • 好吧,当“少数浏览器”似乎是所有主流浏览器sinde NN4 时,可以合理地假设该功能不会很快消失。尽管很可悲,W3C 规范很少反映 Web 开发人员所面临的现实……
  • 再一次,我知道这一点,但如果没有其他原因来准确理解您指出的内容,那么注意规格说明总是很好的 - 它们与现实脱节并且需要更新。顺便说一句,什么是“js-hacks”,为什么需要它?我从您的个人资料中注意到它是您创建的,但很难发现它是什么,因为您的网站缺少信息,而且我没有时间阅读所有文件来寻找它。
  • @Jason:js-hacks 是一个转储独立脚本的地方,以便我可以链接到最新版本;它们中的大多数基本上是无用的或只是为了好玩,但是当您不想使用成熟的框架时,也有一些非常不错;问题是,我懒得写文档,即使某些脚本可能值得向更多公众展示(例如mercurial.intuxication.org/hg/js-hacks/raw-file/tip/capture.js 非常好,并且改变了我的事件处理方法......)
  • @Christoph:啊,好吧 - 我不确定,我认为它可能是某种框架。我是 MochiKit 的忠实用户(现在已经大量使用它 3 年了)并且在过去 3 个月中开始使用 jQuery,但是我喜欢 JavaScript 并且喜欢学习关于它的新东西,也许我会从你的脚本中收集到一些有用的东西。谢谢。
【解决方案4】:

According to the W3C spec只有 BODY 和 FRAMESET 元素提供了一个“onload”事件来附加到。一些浏览器无论如何都支持它,但请注意,它不是实现 W3C 规范所必需的。

可能与本次讨论相关的内容,但不一定是您需要的答案,是本次讨论:

Image.onload event does not fire on Internet Explorer when image is in cache


其他可能与您的需求相关的东西,虽然它可能不相关,是关于支持任何动态加载 DOM 元素的合成“onload”事件的信息:

How can I determine if a dynamically-created DOM element has been added to the DOM?

【讨论】:

  • 这可能是真的,但图像的加载是事实上的标准(自 Netscape Navigator 4 起就已可用)
  • 当然,我从来没有说过这不是他可以指望的东西,只是确保他了解规范 - 忽略规范后果自负。
  • 您提到的 Image.onload 问题是 GWT 特有的 - 请参阅 code.google.com/p/google-web-toolkit/issues/detail?id=863#c5 ; Image.onload 必须在 Image.src 之前设置以避免这种情况,这已经被 Josh 隐式提及
  • @Christoph - 在您的近视眼中,您忘记了两件事:1)我表示它可能与“与此讨论无关”,但更重要的是,2)其他人可能会登陆此页面一天,因为他们遇到了我链接到的问题,并来到这里是因为他们正在搜索他们的具体问题。如果我在 erlang 中发布了一个元组问题的链接,我会看到你不高兴,但我觉得我的 cmets 是相关的。
  • @Jason:我并不难过或任何事情,但您的回答 imo 表明使用图像的 onload 比实际问题更严重;在讨论 vanilla JS 时链接到特定于 GWT 的问题对我来说似乎有点奇怪 - 这不是错误,而是合理且记录在案的行为 - 检查 msdn.microsoft.com/en-us/library/cc197055(VS.85).aspx 的备注部分
【解决方案5】:

看来答案是在 IE 中使用 onreadystatechange,在其他浏览器中使用 onLoad。如果两者都不可用,请执行其他操作。 onLoad 会更好,但 IE 在从缓存加载图像时不会触发它,如下面的答案之一所述。

【讨论】:

  • IE 从缓存加载时触发 onload - 您只需要确保在设置 onload 之前设置 src; Jason 提到的问题是 GWT 特定的,在链接页面上提到了
  • 看来你是对的——感谢您深入到评论链的末尾。现在我需要测试它...
【解决方案6】:

好的,我将尝试在这里总结各种部分答案(包括我的)。

答案似乎是使用 onload,尽管根据标准没有正式要求,但它“得到广泛支持”。请注意,特别是对于 IE,您必须在设置 src 属性之前设置 onLoad,否则从缓存加载图像时它可能不会触发 onload。在任何情况下,这似乎都是最佳实践:在开始触发事件之前设置事件处理程序。在不支持 onload 的情况下,应该假设该功能根本不可用。

【讨论】:

    【解决方案7】:

    注意:我在 2010 年写了这篇文章,当时流行的浏览器是 IE 8/9 beta、Firefox 3.x 和 Chrome 4.x。请将此仅用于研究目的,我怀疑您可以将其复制/粘贴到现代浏览器中并使其正常工作。

    警告:现在是 2017 年,我仍然会时不时地获得积分,请仅将其用于研究目的。我目前不知道如何检测图像加载状态,但可能有比这更优雅的方法......至少我真的希望有。我强烈建议不要在没有更多研究的情况下在生产环境中使用我的代码。

    警告第二部分 Electric Boogaloo: 现在是 2019 年,大多数 jQuery 功能现在都内置在 vanilla JS 中。如果您仍在使用它,可能是时候停下来考虑前往 MDN 并阅读 vanilla JS 必须提供的一些新的有趣的东西。


    我参加这个聚会有点晚了,也许这个答案会对其他人有所帮助......

    如果您正在使用 jQuery,请不要使用现有的事件处理程序(onclick/onmouseover/等),实际上完全停止使用它们。使用他们在API 中提供的事件方法。


    这将在图像附加到正文之前发出警报,因为当图像加载到内存时会触发加载事件。它正在做你告诉它的事情:使用 test.jpg 的 src 创建一个图像,当 test.jpg 加载时会发出警报,然后将其附加到正文。

    var img = $('<img src="test.jpg" />');
    img.load(function() {
        alert('Image Loaded');
    });
    $('body').append(img);
    

    这将提醒,在图像插入正文后,再次执行您告诉它的操作:创建图像,设置事件(未设置 src,因此尚未加载),将图像附加到正文(仍然没有 src),现在设置 src... 现在图像已加载,因此触发事件。

    var img = $('<img />');
    img.load(function() {
        alert('Image Loaded');
    });
    $('body').append(img);
    $img.attr('src','test.jpg');
    

    您当然也可以添加错误处理程序并使用 bind() 合并一堆事件。

    var img = $('<img />');
    img.bind({
        load: function() {
            alert('Image loaded.');
        },
        error: function() {
            alert('Error thrown, image didn\'t load, probably a 404.');
        }
    });
    $('body').append(img);
    img.attr('src','test.jpg');
    

    根据@ChrisKempen 的要求...

    这是一种在 DOM 加载后确定图像是否损坏的非事件驱动方式。此代码是StereoChrome 的文章代码的衍生代码,该文章使用 naturalWidth、naturalHeight 和完整属性来确定图像是否存在。

    $('img').each(function() {
        if (this.naturalWidth === 0 || this.naturalHeight === 0 || this.complete === false) {
            alert('broken image');
        }
    });
    

    【讨论】:

    • 警告:来自 jquery 文档:与图像一起使用时加载事件的警告:开发人员尝试使用 .load() 快捷方式解决的一个常见挑战是在图像(或集合图片)已完全加载。应该注意几个已知的警告。它们是: 它不能始终如一地工作,也不能可靠地跨浏览器 如果图像 src 设置为与以前相同的 src 在 WebKit 中不能正确触发 它不能正确地冒泡 DOM 树 可以停止为图像触发已经存在于浏览器的缓存中
    • 我迟到了,但是如果图像已经添加并且您需要检查它们是否已加载怎么办?感谢您的任何想法/建议! :)
    • @ChrisKempen -- 我在上面的帖子中为你添加了一个非事件驱动的方法,也请查看我的代码派生的原始文章。
    • @paulj - 谢谢!非常有趣的解决方案! +1
    • @paulj 请注意 naturalWidthnaturalHeight 仅与 IE9+ 兼容,请参阅此以获得跨浏览器支持 stackoverflow.com/a/7869044/759452jacklmoore.com/notes/naturalwidth-and-naturalheight-in-ie ,可能受到 css-tricks.com/snippets/jquery/get-an-images-native-width 的启发
    【解决方案8】:

    HTML

    <img id="myimage" src="http://farm4.static.flickr.com/3106/2819995451_23db3f25fe_t.jpg"/>​
    

    脚本

    setTimeout(function(){
        $('#myimage').attr('src','http://cdn.redmondpie.com/wp-content/uploads/2011/05/canarylogo.png').load(function(){
            alert('Main Image Loaded');
    
            $('#myimage').attr('src','image.jpg').bind({
                load: function(){
                    alert('Image loaded.');
                },
                error: function(){
                    alert('Image not loaded.');
                }
            });
        });
    },1000);
    

    JS 小提琴

    http://jsfiddle.net/gerst20051/sLge3/

    【讨论】:

      【解决方案9】:

      使用数据 URI 是可行的方法。但是,使用 SVG 而不是 GIF 提供了更大的灵活性。您可以快速更改大小。只需在 JavaScript 控制台中运行它:

      var width = 1;
      var height = 1;
      'data:image/svg+xml;base64,' +
      btoa(`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"/>`);
      

      示例输出:

      data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz4=
      

      我拼凑了a quick CodePen utility to create transparent SVGs with arbitrary dimensions。它非常基本,因此如果您想为图像添加颜色或其他功能,则需要对其进行修改。

      与单像素图像相比,最大的优势在于它可以保留纵横比。这对于动态大小的图像很重要,因为布局通常在src 更改为真实图像之前执行(如果这是预期目的)。在 src 更改之前,图像将是方形的,这可能是不可取的。

      【讨论】:

        猜你喜欢
        • 2012-05-05
        • 1970-01-01
        • 2010-09-20
        • 2010-10-19
        • 1970-01-01
        • 2011-06-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多