3

假设我有一个 div,并想在该 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,循环它们并使用图像对象预加载每个 URL。全部预加载后,将 HTML 注入输出 div。

4

7 回答 7

2

除非您onload在加载之前将事件连接到每个图像并计算它们,否则没有简单的方法可以判断它们何时全部加载。

于 2012-05-07T18:52:39.280 回答
1

这是一个相对安全的方法( demo ),它使用Deferreds,在 IE 6-9、Chrome 19 和 Firefox 3.6-10、Opera 10.10-11.52、Android 4 和 iOS 5 中测试和工作。

首先,我们将编写一个小型 jQuery 插件,它Deferred为 jQuery 集合中的每个元素返回一个 s 数组。当元素加载时,每个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作为参数传递(它不支持传入Deferreds 数组),因此我们必须传入apply我们的数组。(我可能会这样做$.whenall = function(dfds) { $.when.apply($,dfds); };,以便您的应用程序代码更干净$.whenall( $('#imgs img').loaded() )...

于 2012-05-07T20:39:33.670 回答
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() 快捷方式解决的一个常见挑战是在图像(或图像集合)完全加载时执行一个函数。应该注意几个已知的警告。这些是:

  1. 它不能始终如一地工作,也不能可靠地跨浏览器
  2. 如果图像 src 设置为与以前相同的 src,它不会在 WebKit 中正确触发
  3. 它没有正确地冒泡 DOM 树
  4. 可以停止对已经存在于浏览器缓存中的图像进行触发

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

于 2012-05-07T19:03:04.447 回答
0

我正在考虑的一种方法是使用正则表达式或 jQuery 运行 HTML,查找所有图像 URL,循环它们并使用图像对象预加载每个 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 事件检查它们是否加载。使用错误事件,我们还获得了由于某种原因未正确加载的所有图像的集合。预加载所有图像后,我们可以在“displayResults”函数中将它们注入页面。这大致基于您问题的最后一段。

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

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

于 2012-05-07T19:23:19.107 回答
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

于 2012-05-07T18:52:53.640 回答
0

您是否考虑过使用 jQuery 'on' 事件机制?使用“on”应该允许您在每个图像动态添加到容器和 DOM 时自动将“加载”处理程序绑定到每个图像。

链接: 'on' 函数的 jQuery 文档

如果您使用的是 1.7 之前的 jQuery,则需要使用 'live' 功能,因为 1.7 版本中添加了 'on'。

链接:“live”功能的 jQuery 文档(已弃用)

于 2012-05-07T21:34:58.057 回答
-1

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

当您想显示图片时,您可以执行以下操作:

$("#myDiv").show();
于 2012-05-07T18:56:26.377 回答