jQuery在执行某些操作前等待所有图片加载完成的官方方法是什么?

672

在 jQuery 中,当你执行下面的代码:

$(function() {
   alert("DOM is loaded, but images not necessarily all loaded");
});

它等待DOM加载并执行您的代码。如果所有图像尚未加载,则仍会执行代码。如果我们正在初始化任何DOM内容,例如显示或隐藏元素或附加事件,则这显然是我们想要的。

假设我想要一些动画效果,但在所有图像加载完成之前不希望它运行。在jQuery中是否有官方方法可以实现这一点?

我使用的最佳方法是使用<body onload="finished()">,但除非必须,否则我真的不想这样做。

注意:在Internet Explorer中,jQuery 1.3.1存在一个错误bug,实际上会在执行$function() { }内部的代码之前等待所有图像加载。因此,如果您正在使用该平台,则将获得我正在寻找的行为,而不是上述正确行为。


3
$("img").load() 不起作用吗? - Lucas
1
我认为值得一提的是,如果你设置了尺寸属性,你可以在 ready 函数中安全地执行一些依赖这些尺寸的代码。使用 PHP,您可以通过 http://php.net/manual/en/function.getimagesize.php 在上传时获取它们并存储到数据库中,或在输出到浏览器之前获取它们。 - Alqin
如果你想要做一些令人难以置信的工作,那么请查看下面这个答案中提到的非常好用和流行的imagesloaded JavaScript库:https://dev59.com/_XRB5IYBdhLWcg3wtJGF#26458347 - Adriano
11个回答

1076

使用jQuery时,您可以使用$(document).ready()DOM加载完成时执行一些操作,使用$(window).on("load", handler)在所有其他东西都加载完成时执行一些操作,例如图片。

区别可以从以下完整的HTML文件中看到,前提是您有许多jollyrogerNN JPEG文件(或其他适当的文件):

<html>
    <head>
        <script src="jquery-1.7.1.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                alert ("done");
            });
        </script>
    </head><body>
        Hello
        <img src="jollyroger00.jpg">
        <img src="jollyroger01.jpg">
        // : 100 copies of this in total
        <img src="jollyroger99.jpg">
    </body>
</html>

因此,在DOM准备就绪时,警告框会在图像加载之前出现。如果然后更改:

$(document).ready(function() {

转化为:

$(window).on("load", function() {

如果使用该方法,则在图片加载完成之后才会出现警示框。

因此,要等待整个页面准备完毕,你可以使用类似以下的代码:

$(window).on("load", function() {
    // weave your magic here.
});

32
拍了拍额头 +1 完全忘记了这件事。$(window).load() 会等到图片加载完毕才触发。 - Paolo Bergantino
11
我也曾经有过同样的经历。甚至阅读了一个答案,不知道那是我的答案,但仍然无法理解它。 - Rimian
24
注意 - 在Chromium(我假定是Chrome也一样)下似乎无法正常工作。$(window).ready事件似乎与$(document).ready事件相同,在图像完成之前就已触发。 - Nathan Crause
24
但是它是 $(window).load(function())。 - TJ-
3
您确定这不仅仅是因为IE中的图像已被缓存了吗?如果是这样,它们根本不会触发“load”事件。 此文章可以帮助解决此问题(http://css-tricks.com/snippets/jquery/fixing-load-in-ie-for-cached-images/)。 - Jamie Barker
显示剩余11条评论

160

我编写了一个插件,当元素中的图片加载完毕时可以触发回调,或者每张图片加载完毕时触发一次。

它类似于$(window).load(function() { .. }),但它允许您定义任何选择器进行检查。如果您只想知道是否所有#content中的图片(例如)都已加载完成,则该插件非常适合您。

它还支持加载在CSS中引用的图像,如background-imagelist-style-image等。

waitForImages jQuery 插件

示例用法

$('selector').waitForImages(function() {
    alert('All images are loaded.');
});

在 jsFiddle 上的示例

更多文档可在 GitHub 页面找到。


1
谢谢!$.load() 对我来说不起作用,但这个方法完美解决了问题。 - ashastral
1
@basZero 没有更多的上下文很难判断。请在 Issues 页面上提出问题。 - alex
这个库对我帮助很大,本应该是jquery的一部分。即使是.load()也有一个小问题 http://api.jquery.com/load/ - cr8ivecodesmith
你能更新一下 jsFiddle 吗?(由于 github 不再是 CDN,它已经无法工作了) - Batist
2
它基本上类似于imagesLoaded,但也适用于srcsets。正是我在寻找的!很棒的插件! - Fabian S.
显示剩余3条评论

47

$(window).load() 仅在页面首次加载时有效。如果您正在进行动态操作(例如:单击按钮,等待某些新图像加载),则此方法不起作用。为实现该功能,您可以使用我的插件:

下载

/**
 *  Plugin which is applied on a list of img objects and calls
 *  the specified callback function, only when all of them are loaded (or errored).
 *  @version: 1.0.0 (Feb/22/2010)
 */

(function($) {
$.fn.batchImageLoad = function(options) {
    var images = $(this);
    var originalTotalImagesCount = images.size();
    var totalImagesCount = originalTotalImagesCount;
    var elementsLoaded = 0;

    // Init
    $.fn.batchImageLoad.defaults = {
        loadingCompleteCallback: null, 
        imageLoadedCallback: null
    }
    var opts = $.extend({}, $.fn.batchImageLoad.defaults, options);
        
    // Start
    images.each(function() {
        // The image has already been loaded (cached)
        if ($(this)[0].complete) {
            totalImagesCount--;
            if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
        // The image is loading, so attach the listener
        } else {
            $(this).load(function() {
                elementsLoaded++;
                
                if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);

                // An image has been loaded
                if (elementsLoaded >= totalImagesCount)
                    if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
            });
            $(this).error(function() {
                elementsLoaded++;
                
                if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
                    
                // The image has errored
                if (elementsLoaded >= totalImagesCount)
                    if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
            });
        }
    });

    // There are no unloaded images
    if (totalImagesCount <= 0)
        if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
};
})(jQuery);

1
如果有人需要BatchImagesLoad插件的使用示例:http://www.yankov.us/batchImageLoad/ - Jonathan Marzullo
1
我不是有意冒犯,但是我们不能仅仅依赖于你的话来保证插件的可靠性。正如Yevgeniy Afanasyev的回答中所提到的,imagesLoaded在这方面做得更好,并且涵盖了您提到的用例以及许多其他边角案例(请参见已解决的github问题)。 - Adriano
@hristo.yankov:请更新或删除您的链接。 - Kurt Lagerbier

19

如果你想要在 $(window).load 触发后请求单个图像并在下载完成时得到通知,可以使用图像元素的 load 事件。

例如:

// create a dialog box with an embedded image
var $dialog = $("<div><img src='" + img_url + "' /></div>");

// get the image element (as a jQuery object)
var $imgElement = $dialog.find("img");

// wait for the image to load 
$imgElement.load(function() {
    alert("The image has loaded; width: " + $imgElement.width() + "px");
});

15

目前为止,所有的答案似乎都没有给出最简单的解决方案。

$('#image_id').load(
  function () {
    //code here
});

这个的好处在于,你可以让它在每个图片加载完成后立即触发。 - Top Cat

6
我建议使用imagesLoaded.js JavaScript 库。
为什么不使用 jQuery 的 $(window).load() 呢?
https://stackoverflow.com/questions/26927575/why-use-imagesloaded-javascript-library-versus-jquerys-window-load/26929951 上所述:
这是一个作用域问题。imagesLoaded 允许您目标定位一组图像,而 $(window).load() 则目标定位所有资产,包括所有图像、对象、.js 和 .css 文件以及甚至 iframes。最有可能,imagesLoaded 会比 $(window).load() 更快触发,因为它的目标定位了更小的一组资产。
使用 imagesloaded 的其他好处
  • IE8+ 官方支持
  • 许可证:MIT 许可证
  • 依赖关系:无
  • 大小(已压缩):7kb 已压缩(轻量级!)
  • 下载生成器(有助于减小体积):不必要,已经很小
  • 在 Github 上:是
  • 社区和贡献者:相当大,有 4000 多个成员,尽管只有 13 位贡献者
  • 历史和贡献:作为相对较旧(自 2010 年以来)但仍然活跃的项目而很稳定
资源

4
使用jQuery,我可以做到这一点...
$(function() {
    var $img = $('img'),
        totalImg = $img.length;

    var waitImgDone = function() {
        totalImg--;
        if (!totalImg) alert("Images loaded!");
    };

    $('img').each(function() {
        $(this)
            .load(waitImgDone)
            .error(waitImgDone);
    });
});

Demo : http://jsfiddle.net/molokoloco/NWjDb/


我发现,如果浏览器返回图片的304未修改响应,表示该图片已被缓存,则此方法将无法正常工作。 - JohnyFree

2

使用这种方式,您可以在加载完body或任何其他容器中的所有图像时执行操作(这取决于您的选择)。纯JQUERY,无需插件。

var counter = 0;
var size = $('img').length;

$("img").load(function() { // many or just one image(w) inside body or any other container
    counter += 1;
    counter === size && $('body').css('background-color', '#fffaaa'); // any action
}).each(function() {
  this.complete && $(this).load();        
});

1

我的解决方案类似于molokoloco。写成jQuery函数:

$.fn.waitForImages = function (callback) {
    var $img = $('img', this),
        totalImg = $img.length;

    var waitImgLoad = function () {
        totalImg--;
        if (!totalImg) {
            callback();
        }
    };

    $img.each(function () {
        if (this.complete) { 
            waitImgLoad();
        }
    })

    $img.load(waitImgLoad)
        .error(waitImgLoad);
};

例子:
<div>
    <img src="img1.png"/>
    <img src="img2.png"/>
</div>
<script>
    $('div').waitForImages(function () {
        console.log('img loaded');
    });
</script>

1

使用已打包的imagesLoaded v3.1.8(最小化后为6.8 Kb)。它相对较旧(自2010年以来),但仍是活跃的项目。

您可以在github上找到它: https://github.com/desandro/imagesloaded

官方网站: http://imagesloaded.desandro.com/

为什么它比其他方式更好:

$(window).load() 

因为您可能希望动态加载图片,就像这样:jsfiddle

$('#button').click(function(){
    $('#image').attr('src', '...');
});

1
实际上,imagesloaded不支持跨浏览器更改src属性值。每次都必须创建一个新的图像元素。在Firefox上尝试一下,你会看到问题出现了。 - Adriano
好的,我只在谷歌浏览器和IE-11上进行了测试,但它可以工作。谢谢。 - Yevgeniy Afanasyev
我在我的stackoverflow.com/q/26927575问题中添加了这个跨浏览器问题,具体见"What you cannot do with imagesloaded"部分,可以参考Github上的imagesLoaded相关问题https://github.com/desandro/imagesloaded/issues/121。 - Adriano

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