Javascript - 在所有图像加载后执行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11071314/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 04:17:57  来源:igfitidea点击:

Javascript - execute after all images have loaded

javascript

提问by John Wheal

Having read other people's questions I thought

阅读了其他人的问题,我认为

window.onload=...

would answer my question. I have tried this but it executes the code the instant the page loads (not after the images load).

会回答我的问题。我已经尝试过这个,但它会在页面加载的瞬间(而不是在图像加载之后)执行代码。

If it makes any difference the images are coming from a CDN and are not relative.

如果它有任何区别,则图像来自 CDN 并且不是相对的。

Anyone know a solution? (I'm not using jQuery)

有人知道解决方案吗?(我没有使用 jQuery)

回答by Florian Margaine

Here is a quick hack for modern browsers:

这是现代浏览器的快速破解:

var imgs = document.images,
    len = imgs.length,
    counter = 0;

[].forEach.call( imgs, function( img ) {
    if(img.complete)
      incrementCounter();
    else
      img.addEventListener( 'load', incrementCounter, false );
} );

function incrementCounter() {
    counter++;
    if ( counter === len ) {
        console.log( 'All images loaded!' );
    }
}

Once all the images are loaded, your console will show "All images loaded!".

加载所有图像后,您的控制台将显示“所有图像已加载!”。

What this code does:

这段代码的作用:

  • Load all the images in a variable from the document
  • Loop through these images
  • Add a listener for the "load" event on each of these images to run the incrementCounterfunction
  • The incrementCounterwill increment the counter
  • If the counter has reached the length of images, that means they're all loaded
  • 从文档中加载一个变量中的所有图像
  • 循环浏览这些图像
  • 为每个图像上的“加载”事件添加一个侦听器以运行该incrementCounter函数
  • incrementCounter会递增计数器
  • 如果计数器已达到图像的长度,则表示它们都已加载

Having this code in a cross-browser way wouldn't be sohard, it's just cleaner like this.

以跨浏览器的方式拥有这段代码不会那么难,它只是像这样更干净。

回答by Ajay Beniwal

Promise Pattern will solve this problem in a best possible manner i have reffered to when.js a open source library to solve the problem of all image loading

Promise Pattern 将以最好的方式解决这个问题,我提到 when.js 是一个开源库来解决所有图像加载的问题

function loadImage (src) {
    var deferred = when.defer(),
        img = document.createElement('img');
    img.onload = function () { 
        deferred.resolve(img); 
    };
    img.onerror = function () { 
        deferred.reject(new Error('Image not found: ' + src));
    };
    img.src = src;

    // Return only the promise, so that the caller cannot
    // resolve, reject, or otherwise muck with the original deferred.
    return deferred.promise;
}

function loadImages(srcs) {
    // srcs = array of image src urls

    // Array to hold deferred for each image being loaded
    var deferreds = [];

    // Call loadImage for each src, and push the returned deferred
    // onto the deferreds array
    for(var i = 0, len = srcs.length; i < len; i++) {
        deferreds.push(loadImage(srcs[i]));

        // NOTE: We could push only the promise, but since this array never
        // leaves the loadImages function, it's ok to push the whole
        // deferred.  No one can gain access to them.
        // However, if this array were exposed (e.g. via return value),
        // it would be better to push only the promise.
    }

    // Return a new promise that will resolve only when all the
    // promises in deferreds have resolved.
    // NOTE: when.all returns only a promise, not a deferred, so
    // this is safe to expose to the caller.
    return when.all(deferreds);
}

loadImages(imageSrcArray).then(
    function gotEm(imageArray) {
        doFancyStuffWithImages(imageArray);
        return imageArray.length;
    },
    function doh(err) {
        handleError(err);
    }
).then(
    function shout (count) {
        // This will happen after gotEm() and count is the value
        // returned by gotEm()
        alert('see my new ' + count + ' images?');
    }
);

回答by Ajay Beniwal

Using window.onloadwill not work because it fires once the page is loaded, however images are not included in this definition of loaded.

使用window.onload将不起作用,因为它会在页面加载后触发,但是图像不包含在此加载的定义中。

The general solution to this is the ImagesLoadedjQuery plugin.

对此的一般解决方案是ImagesLoadedjQuery 插件。

If you're keen on not using jQuery at all, you could at least try converting this plugin into pure Javascript. At 93 significant lines of code and with good commenting, it shouldn't be a hard task to accomplish.

如果您根本不想使用 jQuery,您至少可以尝试将此插件转换为纯 Javascript。有 93 行重要的代码和良好的注释,这不应该是一项艰巨的任务。

回答by user

Want a one-liner?

想要单排吗?

Promise.all(Array.from(document.images).filter(img => !img.complete).map(img => new Promise(resolve => { img.onload = img.onerror = resolve; }))).then(() => {
    console.log('images finished loading');
});

Pretty backwards-compatible, works even in Firefox 52 and Chrome 49 (Windows XP era). Not in IE11, though.

非常向后兼容,甚至可以在 Firefox 52 和 Chrome 49(Windows XP 时代)中使用。但是,不在 IE11 中。

Replace document.imageswith e.g. document.querySelectorAll(...)if you want to narrow the image list.

如果要缩小图像列表,请替换document.images为 eg document.querySelectorAll(...)

It uses onloadand onerrorfor brevity. This might conflict with other code on the page if these handlers of the imgelements are also set elsewhere (unlikely, but anyway). If you're not sure that your page doesn't use them and want to be safe, replace the part img.onload = img.onerror = resolve;with a lengthier one: img.addEventListener('load', resolve); img.addEventListener('error', resolve);.

它使用onloadonerror为简洁起见。如果img元素的这些处理程序也在其他地方设置(不太可能,但无论如何),这可能与页面上的其他代码冲突。如果您不确定您的页面是否不使用它们并且想要安全,请用img.onload = img.onerror = resolve;更长的部分替换该部分:img.addEventListener('load', resolve); img.addEventListener('error', resolve);

It also doesn't test whether all images have loaded successfully (that there are no broken images). If you need this, here's some more advanced code:

它也不测试是否所有图像都已成功加载(没有损坏的图像)。如果你需要这个,这里有一些更高级的代码:

Promise.all(Array.from(document.images).map(img => {
    if (img.complete)
        return Promise.resolve(img.naturalHeight !== 0);
    return new Promise(resolve => {
        img.addEventListener('load', () => resolve(true));
        img.addEventListener('error', () => resolve(false));
    });
})).then(results => {
    if (results.every(res => res))
        console.log('all images loaded successfully');
    else
        console.log('some images failed to load, all finished loading');
});

It waits until all images are either loaded or failed to load.

它一直等到所有图像都加载或加载失败。

If you want to fail early, with the first broken image:

如果您想早点失败,请使用第一个损坏的图像:

Promise.all(Array.from(document.images).map(img => {
    if (img.complete)
        if (img.naturalHeight !== 0)
            return Promise.resolve();
        else
            return Promise.reject(img);
    return new Promise((resolve, reject) => {
        img.addEventListener('load', resolve);
        img.addEventListener('error', () => reject(img));
    });
})).then(() => {
    console.log('all images loaded successfully');
}, badImg => {
    console.log('some image failed to load, others may still be loading');
    console.log('first broken image:', badImg);
});

Two latest code blocks use naturalHeightto detect broken images among the already loaded ones. This method generally works, but has some drawbacks: it is said to not work when the image URL is set via CSS contentproperty and when the image is an SVG that doesn't have its dimensions specified. If this is the case, you'll have to refactor your code so that you set up the event handlers before the images begin to load. This can be done by specifying onloadand onerrorright in the HTML or by creating the imgelements in the JavaScript. Another way would be to set srcas data-srcin the HTML and perform img.src = img.dataset.srcafter attaching the handlers.

两个最新的代码块用于naturalHeight在已加载的图像中检测损坏的图像。这种方法通常有效,但有一些缺点:当图像 URL 是通过 CSScontent属性设置的,并且图像是没有指定尺寸的 SVG 时,据说它不起作用。如果是这种情况,则必须重构代码,以便在图像开始加载之前设置事件处理程序。这可以通过在 HTML 中指定onloadand onerrorright 或通过img在 JavaScript 中创建元素来完成。另一种方法是,以集合src作为data-src在HTML并执行img.src = img.dataset.src附接处理之后。

回答by Donovant

 <title>Pre Loading...</title>
 </head>

 <style type="text/css" media="screen"> html, body{ margin:0;
 padding:0; overflow:auto; }
 #loading{ position:fixed; width:100%; height:100%; position:absolute; z-index:1; ackground:white url(loader.gif) no-repeat center; }**
 </style>

 <script> function loaded(){
 document.getElementById("loading").style.visibility = "hidden"; }
 </script>

 <body onload="loaded();"> <div id="loading"></div>

 <img id="img" src="avatar8.jpg" title="AVATAR" alt="Picture of Avatar
 movie" />


 </body>

回答by Baz1nga

You can have the onload event on the image that can callback a function that does the processing... Regarding how to handle if all images are loaded, I am not sure if any of the following mechanisms will work:

您可以在图像上使用 onload 事件,该事件可以回调执行处理的函数...关于如何处理是否加载了所有图像,我不确定以下任何机制是否有效:

have a function that counts the number of images for which onload is called, if this is equal to the total number of images on your page then do your necessary processing.

有一个函数来计算调用 onload 的图像数量,如果这等于您页面上的图像总数,则进行必要的处理。

回答by monners

A little late to the game, but I've found the following method to be the most straightforward:

游戏有点晚了,但我发现以下方法是最直接的:

function waitForImages () {
  let isLoading = true

  while (isLoading) {
    const loading = [].slice.call(document.images).filter(img => img.complete !== true)
    if (!loading.length > 0) {
      isLoading = true
      return
    }
  }
}

Note that this is blocking code (useful if you're trying to ensure images are loaded in something like phantomjs)

请注意,这是阻塞代码(如果您试图确保图像以 phantomjs 之类的方式加载,则很有用)

回答by Tamar Dahan

This works great:

这很好用:

$(function() {
 $(window).bind("load", function() {
    // code here
 });
});

回答by PPac

I was about to suggest the same thing Baz1nga said.

我正要提出 Baz1nga 所说的同样的话。

Also, another possible option that's maybe not as foolproof but easier to maintain is to pick the most important/biggest image and attach an onload event to only that one. the advantage here is that there's less code to change if you later add more images to your page.

此外,另一种可能不是万无一失但更易于维护的选项是选择最重要/最大的图像并将 onload 事件仅附加到该图像。这里的优点是,如果您稍后向页面添加更多图像,则需要更改的代码更少。