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

时间:2012-06-17 12:31:56

标签: javascript

读过其他人的问题我想

window.onload=...

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

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

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

9 个答案:

答案 0 :(得分:27)

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

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

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

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

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

此代码的作用:

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

以跨浏览器的方式使用此代码不会如此很难,它就像这样更清晰。

答案 1 :(得分:18)

想要一线吗?

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');
});

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

document.images替换为例如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');
});

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

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

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);
});

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

答案 2 :(得分:12)

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?');
    }
);

答案 3 :(得分:2)

使用window.onload将无效,因为一旦页面加载就会触发,但是此加载定义中不包含图像。

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

如果您热衷于完全不使用jQuery,那么至少可以尝试将此插件转换为纯Javascript。在93个重要的代码行和良好的评论中,它不应该是一项艰巨的任务。

答案 4 :(得分:1)

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

有一个函数可以计算调用onload的图像数量,如果这等于页面上的图像总数,那么就进行必要的处理。

答案 5 :(得分:1)

 <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>

答案 6 :(得分:1)

游戏稍晚,但我发现以下方法最直接:

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
    }
  }
}

请注意,这是阻止代码(如果您尝试确保图像像phantomjs一样加载,则非常有用)

答案 7 :(得分:0)

我打算建议同样的事情Baz1nga说。

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

答案 8 :(得分:0)

这很棒:

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