【问题标题】:jQuery: Dynamic image handling (waiting for load)jQuery:动态图像处理(等待加载)
【发布时间】:2011-02-02 12:45:06
【问题描述】:

我正在尝试编写一个具有内置功能的插件,以等待页面上的所有图像都被加载,然后再自行执行。 $(window).load() 仅在页面的初始加载时才有效,但如果有人想通过 AJAX 拉下一些包含图像的 HTML,它就不起作用了。

有没有什么好的方法可以做到这一点并实现它,以便它可以在插件中自包含?我试过循环遍历$('img').complete,但我知道这不起作用(图像永远不会加载,并且浏览器在“脚本需要很长时间才能完成”错误下崩溃)。有关我正在尝试执行的操作的示例,请访问我正在寻找包含该插件的页面:

http://www.simplesli.de

如果您转到“更多用途”部分(在导航栏上单击它),您会看到图像幻灯片无法正确加载。我知道当前的代码不起作用,但它只是保持原位,直到我弄清楚为止。

编辑:尝试此解决方案,但它不起作用:

if($('.simpleSlide-slide img').size() > 0) {
    var loaded_materials = $('.simpleSlide-slide img').get();
} else {
    var loaded_materials = $('.simpleSlide-slide').get();
}

$(loaded_materials).live('load', function() {
         /* Image processing and loading code */
    });

【问题讨论】:

    标签: jquery image load callback


    【解决方案1】:

    您是否想过使用live() 绑定到所有当前和未来的img 元素?

    $('img').live('load', function ()
    {
        alert("image loaded: "+this.src);
    });
    

    更新后,我可以看到您遇到的问题。 live() 在选择器上效果最好,而在 jQuery 包装的元素数组上使用它。像这样使用live() 与使用bind() 没有什么不同。你应该尝试这样的事情:

    if($('.simpleSlide-slide img').size() > 0) {
        var loaded_materials = '.simpleSlide-slide img';
    } else {
        var loaded_materials = '.simpleSlide-slide';
    }
    
    $(loaded_materials).live('load', function() {
             /* Image processing and loading code */
    });
    

    【讨论】:

    • 我昨晚试过了,但它似乎没有用,除非我完全错过了语法,但 live 对我来说似乎并不复杂。我相信它本身并不支持'load' 作为一个事件...
    • 你是一台机器!我正在输入我的答案:P 这不公平;)
    • @dclowd9901:文档没有提到不受支持的事件。只是A string containing a JavaScript event type, such as "click" or "keydown". 它甚至声称支持自定义事件,所以我确信它可以支持标准事件:-)
    • @Andy 是的,它确实支持所有事件,但仅在最新版本的 jquery 中。它过去只适用于可用事件的子集,他们必须快速修复它,因为人们一直在滥用 live() 函数。我自己更喜欢跟踪我在做什么,如果可能的话,使用 bind()。
    • 又试了一次。这就像它不是 .live() 或其他东西的功能性使用。使用 Firebug 断点,它会到达该行,然后进行转储。它不会再进一步​​了。
    【解决方案2】:

    我认为您需要将一个函数绑定到全局 ajaxSuccess,然后将加载事件绑定到页面上的每个图像。

    $.ajaxSuccess(function(){
     $('img').load(function(){
      //Your code here
     });
    });
    

    或者当你期望有很多图片时:

    $.ajaxSuccess(function(){
     $('img:not(.loaded)').addClass('.loaded').bind('load',function(){
      //Your code here
     });
    });
    

    如果上述任何代码不能正常工作,Tou 可能希望将代码放入回调中,以便在添加 html 后将其添加到站点。在上述函数中使用 setTimeout 也可能有所帮助。

    [编辑]

    如果您知道要加载多少图像,您可以在服务器端代码中生成图像<img src="something" onload="$.imgHello()" /> 并在每个$.imgHello() 函数调用中增加一些计数器。但这不是我推荐给任何人的解决方案。

    【讨论】:

    • 如果页面上碰巧有数百张图片,那么只选择新的图片应该比将新的加载功能绑定到所有图片更快。
    • 但是我会为页面上的尽可能多的图像执行相同的功能吗?这不会同样减慢一切吗?我不断回到这个想法,如果只有某种方式我可以让脚本知道页面上有多少图像(它可以),并且每个图像都可以以某种方式通知脚本它的完成,然后脚本可以在完成通知后依次执行一个功能,那么我会很高兴。 javascript 有那么大的能力吗?
    • 事实上就是这样。但仅适用于由单个 ajax 调用生成的图像。在将图像放在页面上之前,您不能将任何内容绑定到事件。您可以做的只有一个小技巧。见编辑
    • 糟糕,我认为jQuery .load() method 不是事件处理程序,它是内容重写器。也许改为$('img').one('load', function(){
    【解决方案3】:

    在尝试以几乎所有可以想象的方式完成这项任务之后,这个任务终于奏效了,非常感谢 Naugtur 为我指明了正确的方向:

    var no_of_images = $('img').size();
    
    $.extend(no_of_images);
    
    if(no_of_images > 0) {
    
        var images = new Array();
        var i = 0;
        $('img').each( function() {
            images[i] = $(this).attr('src');
            i++;
        });
    
        i = 0;
    
        $(images).each( function(){
            var imageObj = new Image();
            imageObj.src = images[i];
            $(imageObj).load( function() {
                no_of_images--;
                i++;
                if(no_of_images == 0){
                    functionToPerform();
                }
            });
        });
    } else {
        functionToPerform();
    }
    

    为了快速解释正在发生的事情,我将使用一个类比。想象每张图片都是您聚会的客人。灯灭了。你打开灯,然后跑到每个客人​​面前,给他们一张纸、一支笔和一部手机,同时计算你把材料分发给了多少人。他们都开始疯狂地画画,然后他们一画完,就会打电话告诉你。对于每一个跟注的人,你都会从你的棋盘上划掉一个计分。当最后一个人给你打电话时(当你的黑板上的计数标记用完时),你告诉他们挂断电话并给披萨店的人打电话。现在是披萨时间。如果一开始没有客人,你自己打电话给比萨人。

    如果你在想“他为什么要为每个 $.load() 创建一个 Image() 对象,那么,我尝试采用传统的 jQuery 路线,使用直接的 jQuery 样式选择器而不是图像对象。看起来完全被忽略(导致页面崩溃)。我尝试将Image().onLoad 结合使用,并且在不崩溃页面的情况下起作用,但它没有执行我编写它的功能。

    这段代码是独立的,所以我想它可以复制粘贴到任何图像加载应用程序中。它对我来说似乎足够小,以免打扰。 functionToPerform() 基本上充当您希望等待执行的任何功能,直到加载所有图像(在我的情况下,它是整个插件)。涂鸦。

    【讨论】:

    • 你为什么打电话给$.extend(no_of_images);
    【解决方案4】:

    循环遍历图像并调用$('img').complete 的问题在于浏览器 UI 是单线程的,因此您永远不会给它机会加载图像,因为它总是在您的循环中。您可以使用setTimeout 允许浏览器工作。例如,

    $.get("whatever",function(html) {
       $('#foo').html(html);
       var images = getTheImages();
       function checkImages() {
          var done = true;
          $.each(images,function() {
             done = done && this.complete;
             return done;
          });
          if(done) {
            fireEvent();
          } else {
            setTimeout(checkImages,100); // wait at least 100 ms and check again
          }
       }
    });
    

    【讨论】:

    • 我实际上也试过这个。它仍然没有在正确的时间回击。也许我的方法是错误的,但它看起来和你在这里写的很相似。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 2017-09-30
    相关资源
    最近更新 更多