javascript 懒加载图片 - 与浏览器无关的方式来检测何时加载图像



懒加载阮一峰 jq懒加载 (9)

在IE中,您可以onreadystatechange。 有载入,但我读了可怕的东西 。 jQuery用“就绪”很好地包装了DOM的加载事件。 我似乎只是不知道另一个很好的库的图像加载实现。

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

我对“本机”JavaScript解决方案或指向完成工作的库的指针感到满意。 那里有很多图书馆,我确信这是我不知道正确的图书馆的情况。 也就是说,我们已经是jQuery用户了,所以我并不急于为了获得这个功能而添加一个非常大的库。


Answers

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

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

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

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

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

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


我发现唯一可靠的方法是在客户端这样做,就像这样......

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

如果我没有在javascript中出错,那么图片标签会有事件onload和onerror

这是我用来隐藏破碎图像的一段代码

在样式标签中

img.failed{
   display:none;
}

使用img onerror我有一段javascript做了this.className =失败,它会隐藏图像,如果它错误

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


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

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

我参加这个派对有点晚了,也许这个答案会帮助别人......

如果你正在使用jQuery,请不要理会股票事件处理程序(onclick / onmouseover / etc),实际上只是完全停止使用它们。 使用他们在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');
    }
});

根据W3C规范只有 BODY和FRAMESET元素提供附加的“onload”事件。 有些浏览器无论如何都支持它,但请注意,不需要实现W3C规范。

可能与此讨论相关的事情,但不一定是您需要的答案,是这个讨论:

当图像在缓存中时,Image.onload事件不会在Internet Explorer上触发

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

如何确定是否已将动态创建的DOM元素添加到DOM中?


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/


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

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


似乎答案是在IE中使用onreadystatechange,在其他浏览器中使用onLoad。 如果两者都不可用,请做其他事情。 onLoad会更好,但IE从缓存中加载图像时不会触发它,如下面的答案中所述。


这真的很棘手。 鉴于以下要求,似乎没有解决方案。

  • 该页面包含您无法控制的iframe
  • 无论TAB更改(ctrl + tab)还是窗口更改(alt + tab)触发的更改都要跟踪可见性状态更改

这是因为:

  • 页面可见性API可以可靠地告诉你标签更改(即使使用iframe),但它不能告诉你用户何时更改窗口。
  • 只要iframe没有焦点,监听窗口模糊/焦点事件就可以检测到alt +制表符和ctrl +制表符。

考虑到这些限制,可以实现一个解决方案 - 页面可见性API - 窗口模糊/焦点 - document.activeElement

这是能够:

  • 1)当父页面有焦点时,ctrl + tab:YES
  • 2)当iframe具有焦点时,ctrl + tab:YES
  • 3)当父页面有焦点时,alt +标签:是
  • 4)当iframe具有焦点时,alt +标签: NO < - 无赖

当iframe拥有焦点时,您的blur / focus事件根本不会被调用,并且页面Visibility API将不会在alt +选项卡上触发。

我建立在@ AndyE的解决方案上,并在这里实现了这个(几乎不错的)解决方案: https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html ://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html(对不起,我在JSFiddle方面遇到了一些麻烦)。

这也可以在Github上找到: https://github.com/qmagico/estante-componentshttps://github.com/qmagico/estante-components

这适用于铬/铬。 它适用于Firefox,除了它不加载iframe的内容(任何想法为什么?)

无论如何,要解决最后一个问题(4),唯一的方法就是在iframe上侦听模糊/焦点事件。 如果你对iframe有一些控制,你可以使用postMessage API来完成。

https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test2.html

我还没有用足够的浏览器测试过。 如果您可以找到更多有关这不起作用的信息,请在下面的评论中告诉我们。





javascript dom