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

Joh*_*eal 14 javascript

读过其他人的问题后,我想

window.onload=...
Run Code Online (Sandbox Code Playgroud)

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

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

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

use*_*ser 42

想要单排吗?

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');
});
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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');
});
Run Code Online (Sandbox Code Playgroud)

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

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

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);
});
Run Code Online (Sandbox Code Playgroud)

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

  • 很好的答案。我发现了一种破损的边缘情况:在 Firefox 上,当由于协议未知而从未尝试加载图像时,“<img>”可能无限期地处于“completed===false”状态。例如,`<img src="aaaa:">`。您的代码仍然有效,因为触发了“onerror”,但当您动态运行代码时,它会失败。我[在这里](http://jsfiddle.net/f9ku7jn4/)做了一个演示。也许是火狐浏览器的错误? (2认同)

Flo*_*ine 31

这是现代浏览器的快速入侵:

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!' );
    }
}
Run Code Online (Sandbox Code Playgroud)

加载完所有图像后,控制台将显示"所有图像已加载!".

这段代码的作用:

  • 将所有图像加载到文档中的变量中
  • 循环浏览这些图像
  • 在每个图像上为"load"事件添加一个侦听器以运行该incrementCounter函数
  • incrementCounter会递增计数器
  • 如果计数器已达到图像的长度,则表示它们已全部加载

以跨浏览器的方式使用这些代码并不会那么难,它就像这样清洁.

  • 两个注意事项:如果您的脚本加载较晚,您可能会错过一些导致脚本永远无法完成的事件.此外,您的浏览器可能无法加载最初由css隐藏的所有图像. (3认同)

Aja*_*wal 15

Promise Pattern将以最好的方式解决这个问题我已经参考了.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?');
    }
);
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。现代解决方案,效果很好。荣誉阿杰 (2认同)