【问题标题】:jQuery Ajax wait until all images are loadedjQuery Ajax 等到所有图像都加载完毕
【发布时间】:2011-06-14 01:40:12
【问题描述】:

我正在尝试使用运行良好的 jQuery 执行 Ajax 调用。我使用成功事件来显示数据。然而,似乎一旦加载外部 HTML 文件就会触发成功。如果有大图像,它们会在显示后继续加载。有没有办法在所有内容完全加载后显示内容?代码如下:

$('#divajax').html('<br><div style="text-align: center;"><img src="res/ajax-loader.gif"></div>');
$.ajax({
    cache: false,
    url: 'ajax/content.php',
    success: function(data) {
          $('#divajax').html(data);
    }
});

【问题讨论】:

    标签: jquery ajax loading


    【解决方案1】:

    @alex 编写的插件由于某种原因对我不起作用……我不知道为什么。但他的代码确实激发了我想出一个对我有用的更轻量级的解决方案。它使用 jquery 承诺。请注意,与 @alex 的插件不同,这不会尝试考虑元素上的背景图像,仅考虑 img 元素。

    // Fn to allow an event to fire after all images are loaded
    $.fn.imagesLoaded = function () {
    
        // get all the images (excluding those with no src attribute)
        var $imgs = this.find('img[src!=""]');
        // if there's no images, just return an already resolved promise
        if (!$imgs.length) {return $.Deferred().resolve().promise();}
    
        // for each image, add a deferred object to the array which resolves when the image is loaded (or if loading fails)
        var dfds = [];  
        $imgs.each(function(){
    
            var dfd = $.Deferred();
            dfds.push(dfd);
            var img = new Image();
            img.onload = function(){dfd.resolve();}
            img.onerror = function(){dfd.resolve();}
            img.src = this.src;
    
        });
    
        // return a master promise object which will resolve when all the deferred objects have resolved
        // IE - when all the images are loaded
        return $.when.apply($,dfds);
    
    }
    

    然后你可以像这样使用它:

    $.ajax({
        cache: false,
        url: 'ajax/content.php',
        success: function(data) {
            $('#divajax').html(data).imagesLoaded().then(function(){
                // do stuff after images are loaded here
            });
        }
    });
    

    希望这对某人有所帮助。

    请注意,使用上面的代码,如果其中一个图像错误(例如,因为 URL 错误),则无论如何都会解决承诺并忽略错误。这可能是您想要的,但是,根据您的情况,如果图像无法加载,您可能希望中止正在执行的任何操作。在这种情况下,您可以按如下方式替换 onerror 行:

    img.onerror = function(){dfd.reject();}
    

    并像这样捕获错误:

    $('#divajax').html(data).imagesLoaded().done(function(){
        // do stuff after all images are loaded successfully here
    }).fail(function(){
        // do stuff if any one of the images fails to load
    });
    

    【讨论】:

    • 这看起来可能会造成内存泄漏。每次进行 ajax 调用时,都会在内存中为页面上的每个图像创建一个副本,并将一个事件附加到每个新图像对象,在执行完 imagesLoaded 函数后将图像对象保留在内存中。一旦加载了所有重复的图像对象,它们什么时候从内存中删除?执行onload事件回调后直接?
    • @MarkEntingh - 关于内存泄漏,您可能是对的 - 我不确定。一旦 promise 被解决,闭包中是否还有对 Image 对象的引用?我不认为有,所以 JS 应该垃圾收集它。如果您担心这一点,可以使用在函数外部定义的 Image 对象数组,并在“then”函数中显式删除它们。注意 - 您说的是“页面上每个图像的副本” - 只有将其应用于整个文档时才会出现这种情况 - $(document).imagesLoaded()。通常它会是一个小子集,或者只是一个图像。
    • 我建议同时处理 onerror 事件,否则回调可能永远不会被调用。
    • 好点@YM_Industries - 我已经更新了代码以纳入您的建议。
    • @Kril 如果您还需要包含背景图像,则必须找到一种方法来搜索“this”元素正在使用的所有背景图像并将它们添加到 $imgs 数组一开始。
    【解决方案2】:

    当丹尼尔的解决方案中的插件找不到图像时,我遇到了一个小错误。

    以防万一其他人遇到同样的问题:

    变化:

    // if there's no images, just return an already resolved promise
    if (!$imgs.length) {return $.Deferred.resolve().promise();}
    

    收件人:

    // if there's no images, just return an already resolved promise
        if (!$imgs.length) {
            var dfd = $.Deferred();
            return dfd.resolve().promise();
        }
    

    【讨论】:

      【解决方案3】:

      您可以使用与JavaScript和jQuery一起使用的imagesloaded插件,尝试在加载内容上使用ajax内部success回调函数,并在imagesloaded回调函数未触发时隐藏所有内容,请参见下面的示例代码

      $.ajax({
          cache: false,
          url: 'ajax/content.php',
          success: function(data) {
              var $divajax = $('#divajax').html(data).hide();
              $divajax.imagesLoaded(function() {
                   $divajax.show();
               });
      
          }
      });
      

      【讨论】:

        【解决方案4】:

        试试这个代码。它工作正常。

        $.ajax({ 网址:“../api/listings”, 类型:'GET', 成功:函数(html){ $('#container').append(html); $('#container img').on('load', function(){console.log('images loaded')}); }; });

        【讨论】:

          【解决方案5】:

          这会在每个 img 加载时单独触发:

          $('img').on('load', function() {
                // do something
          });
          

          我用过:

          var loaded = 0;
          $('img').on('load', function() {
             loaded++;
             if(loaded == $('img').length){
                // do something
             }
          });
          

          【讨论】:

            【解决方案6】:

            您可以将某些内容绑定到加载事件以了解它们何时完成:

            $('<img>').bind('load', function() {
                $(this).appendTo('body');
            });
            

            或者你可以使用this plugin

            【讨论】:

            • 天哪,你不知道对我有多大帮助,我一直在寻找解决方案好几个小时......非常感谢:D
            • .on() 现在显然比 .bind() 更推荐
            【解决方案7】:

            你可以使用我的 jQuery 插件,waitForImages...

            $.ajax({
                cache: false,
                url: 'ajax/content.php',
                success: function(data) {
            
                     $('#divajax').html(data).hide().waitForImages(function() {
                         $(this).show();
                     });
            
                }
            });
            

            这会将内容加载到您的元素中,将其隐藏,然后在后代img 元素加载后重新显示。

            【讨论】:

            • @alex,我也可以用它来追加吗?基本上我正在无限滚动并将元素与其他图像一起追加到现有容器中
            • @alex,非常感谢你的插件,我把我的容器 div 附加到了附件中,它工作得很好
            【解决方案8】:

            我认为最好的是使用这个

            $(window).ready(function(){ //load your ajax})
            

            【讨论】:

            • 这不起作用,因为 $(document).ready()$(window).load() 在 AJAX 请求后不会触发。
            【解决方案9】:
            $('#divajax').html('<br><div style="text-align: center;"><img src="res/ajax-loader.gif"></div>').load(function() {
            $.ajax({
                cache: false,
                url: 'ajax/content.php',
                success: function(data) {
                      $('#divajax').html(data);
                }
            });
            });
            

            【讨论】:

              【解决方案10】:

              研究使用 jquery 的 .load()

              其中有以下描述:

              当一个元素和所有子元素都被完全加载后,加载事件会被发送到该元素。此事件可以发送到与 URL 关联的任何元素:图像、脚本、框架、iframe 和窗口对象。

              【讨论】:

              • 问题是我无法关闭带负载的异步调用并正确设置缓存选项?
              猜你喜欢
              • 2019-02-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-12-19
              • 1970-01-01
              • 2020-03-17
              相关资源
              最近更新 更多