使用JavaScript动态添加带有<img>标签的HTML,如何判断图像何时加载完成?

3
假设我有一个div,想要将一些HTML注入到其中。HTML中包含1个或多个图像。
是否可以使用纯JavaScript或jQuery来确定何时加载了这些图片?
因此,如果我执行以下操作,您能否将事件侦听器放置在单个元素上以告知内容(包括图像)何时准备好:
var html = "<p>Some text <img src='image.jpg' /></p><p>Some more text <img src='image2.jpg' /></p>";
$("div.output").html(html);

每次图像都不同,所以我不能使用JavaScript图像对象预加载。
我考虑的一种方法是使用正则表达式或jQuery运行HTML,找到所有图像URL,循环遍历它们并使用图像对象预加载每个图像。当全部预加载完成后,再将HTML注入输出div。

不要使用正则表达式:https://dev59.com/X3I-5IYBdhLWcg3wq6do - Diodeus - James MacFarlane
7个回答

2
除非在每个图片加载之前都连接一个onload事件并计数,否则没有简单的方法来判断它们何时全部加载完成。

1
即使如此,现在并不是所有浏览器都能以相同的方式处理带有图像的onload事件,特别是对于缓存的图像和类似的src属性。 - David Hoerster

1

这里有一个相对稳定的方法(演示),它使用了Deferreds,在IE 6-9、Chrome 19、Firefox 3.6-10、Opera 10.10-11.52、Android 4和iOS 5中经过测试并且可行。

首先,我们将编写一个小型的jQuery插件,为jQuery集合中的每个元素返回一个Deferred数组。每个Deferred将在元素加载时解决;如果元素加载失败或(可选)超过timeout秒,则会被拒绝。

$.fn.loaded = function(opts) {
    var o = $.extend({timeout:10000}, opts) // Merge default options with supplied options
        , r = []; // Return value

    this.each(function() {
        var dfd = new $.Deferred(), el = $(this), to;
        if (o.timeout) to = setTimeout(function() {
            done();
            dfd.reject();
        }, o.timeout);
        el.bind('load.dfdl', function() {
            done();
            dfd.resolve();
        }).bind('error.dfdl', function() {
            done();
            dfd.reject();
        });

        function done() { // internal clean-up
            clearTimeout(to);
            el.unbind('.dfdl');
        }
        r.push(dfd.promise());
    });
    return r;
};

超时机制将防止浏览器从未实际触发任何事件的情况。我在这里设置了默认超时时间为10秒;在现实世界中,您可能希望将其缩短。

现在我们将生成10个随机大小的placekittens,用作示例中的图像。

var imgs=[];
for (var i = 0; i < 10; i++) imgs.push('<img src="http://placekitten.com/' + rnd() + '/' + rnd() + '"> ');
$('#imgs').html(imgs.join());

最后,我们将用一些魔法将所有东西集成在一起:

$.when.apply($, $('#imgs img').loaded({timeout:10000}) ).done(function() {
    alert('loaded successfully');
}).fail(function() {
    alert('load failed or timed out');
});

$.when 创建一个主 Deferred,只有当所有子 Deferred 解决时才会被解决,或者在子 Deferred 拒绝时拒绝。它通常希望您将每个 Deferred 作为参数传递(不支持传递 Deferred 数组),因此我们必须 apply 我们的数组。(我可能会做 $.whenall = function(dfds) { $.when.apply($,dfds); }; 这样你的应用程序代码就有了更清晰的 $.whenall( $('#imgs img').loaded() )...


0

试试这个:

$("#preload_div").html(
    '<img src="image.png" alt="preload" class="preload" width="0" height="0">'
);

事件处理程序可以绑定到图像:

$('preload').load(function () {
    var html = "<p>Some text <img src='image.jpg' /></p><p>Some more text <img src='image2.jpg' /></p>";
    $("div.output").html(html);
});

当然,您需要为每个图像都加入.each()以循环遍历所有图像。

编辑:在我的一个AJAX网站上,我预加载了下一个需要的图像,因此当用户点击“下一个”按钮时,新内容所需的图像已经被缓存。请参见http://funl.es/p/1


如果你选择这条路,你应该记住 load 事件处理程序的注意事项:http://api.jquery.com/load-event/ - David Hoerster

0

我认为你应该在将图像插入HTML后绑定加载处理程序。

演示

    //Add image
    $('#result').append('<img src= "<Your_Image_URL>" width="300" height="300"/>');

    //Bind handler also add condition to not bind images that was not added before.
    $('#result').find('img').not('.loaded').on('load', function () {
        alert('Image Loaded');
        //Add code that you want to do after the image is added
    }).addClass('loaded');

请注意,当与图像一起使用时,load事件的注意事项。

开发人员尝试使用.load()快捷方式解决的常见问题是,在图像(或一组图像)完全加载后执行函数。这方面有几个已知的注意事项应该注意。它们是:

  1. 它在不同浏览器之间不能保持一致和可靠的工作
  2. 如果图像src设置为与之前相同的src,则在WebKit中无法正确触发
  3. 它不能正确地冒泡到DOM树
  4. 对于已经存在于浏览器缓存中的图像,可能会停止触发

参考资料:http://api.jquery.com/load-event/


如果您选择这条路线,请记住“load”处理程序周围的警告:api.jquery.com/load-event - David Hoerster
@DavidHoerster 确实,谢谢指出。我已经在帖子中更新了它。 - Selvakumar Arumugam

0
我正在考虑的一种方法是使用正则表达式或jQuery遍历HTML,找到所有图像URL,循环遍历它们并使用图像对象预加载每个图像。当所有图像都被预加载后,再将HTML注入输出div中。
var imagesLoaded = [];
var imagesErrored = [];

$('img').each(function() {
     $(this).load(function() {
         imagesLoaded.push($(this).attr("src"));
         if( (imagesLoaded.length + imagesErrored.length) == $('img').length ) {
             displayResults(imagesLoaded, imagesErrored);

         } 
     });
     $(this).error(function() {
         imagesErrored.push($(this).attr("src"));
         if( (imagesLoaded.length + imagesErrored.length) == $('img').length ) {
             displayResults(imagesLoaded, imagesErrored);
         } 

});

function displayResults(imagesLoaded, imagesErrored) {
    for(var i = 0; i < imagesLoaded.length; i++) {
        alert(imagesLoaded[i] + " has loaded successfully.");
        $('#myDiv').append("<img src='" + imagesLoaded[i] + "' />");
    }
    for(var i = 0; i < imagesErrored.length; i++) {
        alert(imagesLoaded[i] + " did NOT load successfully.");
    }
}

上述代码循环遍历所有图像,并使用load事件检查它们是否已加载。使用error事件,我们还可以获取所有因某种原因未正确加载的图像集合。在所有图像都被预加载后,我们可以在“displayResults”函数中将它们注入到页面中。这基本上是根据您问题中的最后一段进行的。

然而,它不使用正则表达式,因为它们不是操作DOM的正确工具。幸运的是,JavaScript和jQuery为我们提供了执行DOM操作和解析活动所需的工具。

最后,从您的问题中,听起来您可能对知道哪些图像成功加载感兴趣。从load和error事件构建的上述集合将为您提供这些详细信息,如果您需要的话。


0

你考虑过使用jQuery的'on'事件机制吗?使用'on'应该可以让你自动绑定'load'处理程序到每个图像,因为它被动态添加到容器和DOM中。

链接: jQuery 'on'函数文档

如果你使用的是1.7之前的jQuery版本,你需要使用'live'函数,因为'on'是在1.7版本中添加的。

链接: jQuery 'live'函数文档(已弃用)


-1

我认为没有简单的方法来做到这一点。你可以做的是将所有图片加载到一个隐藏的 div 中(display: none)。

当你想要显示图片时,可以这样做:

$("#myDiv").show();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接