如何确定页面中的N个图片都已经加载完成,并且确定了在页面中的尺寸?

我们做的一款Web App,其中会从后台获取DOM结构(包在一个section元素里),然后append到一个container div下面。
之后,需要计算一下新加进来的section的尺寸信息。
我们发现,一旦这个section里含有一些img元素,就会导致append后,马上计算尺寸,拿到的数据是不准确的。
我们已经用过Mutation Observer来监控container下的元素变化,延后了计算时间。但是这个方法无法解决图片的问题。

请问,我们怎么抓住这样一个时点:所有图片都已加载完毕,并且之后不会再影响页面的布局。

多谢各位大神。

阅读 3.2k
7 个回答

效果图

clipboard.png

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>

<body style="background:#eee">
    <script>
     const images = [
        "https://avatar-static.segmentfault.com/102/500/1025005915-54cb538538eea_small",
        "https://static.segmentfault.com/v-5b8f9b7e/global/img/user-64.png",
     ];
     Promise.all(
        images.map(url=>new Promise((resolve,reject)=>{
            const img = new Image();
            img.addEventListener("load",function(){
                // 增加自定义属性表明加载成功了没有
                this.__isOK__ = true;
                resolve(this);
            },{once:true})
            img.addEventListener("error",function(){
                this.__isOK__ = false;
                resolve(this);
            },{once:true});
            
            img.src = url;
        }))
     ).then(arr=>{
        const success = arr.filter(img=>img.__isOK__);
        console.log(`加载完毕。共加载了${arr.length}张图片。其中成功了${success.length}张。`)
        console.log(`成功的图片的尺寸分别为:\n${success.map(img=>`宽${img.naturalWidth},高${img.naturalHeight}`).join("\n")}`);
     })
    </script>
</body>
</html>

这时候img标签已经存在了,可以获取到标签的个数吧,可以给imgonload/error的回调了吧,然后在回调里面计数就知道图片是不是已经成功或失败了吧。

唔,有个小问题,确定这个尺寸的目的是啥

这是预加载的处理,

var imgLoad = function (url, callback) {
        var img = new Image();
         img.src = url; 
       if (img.complete) {
          callback(img.width, img.height);
       }  else {
         img.onload = function () { 
             callback(img.width, img.height);
             img.onload = null; 
          }
        }

如果要判断所有图片已加载,那么有两个方法:

  1. 侦听所有图片的 load 事件(或 onload='')
  2. 定时遍历图片,检查它们的 naturalWidth 属性

首先过滤出来后来返回的dom结构里面的所有图片。
然后遍历进行图片的onload事件监听。
然后计数,如果当前触发回调的onload时间里面的计数数量等于img数组长度触发callback(进行外层容器宽高的计算。)

建议,获取数据之后,先把所有图片做一个预加载,然后再 append到 dom中。
这样的预加载实现方式根据 运行环境的不同有很多,这里简单示意(利用promsie):

function _loadImage(item) {
  return new Promise((resolve, reject) => {
    var image = new Image();
    image.onload = () => {
      resolve();
    };
    image.onerror = err => {
      resolve();
    };
    image.src = item.src;
  });
}
function loadeImages(imgs) {
  const tasks = imgs.map(img => _loadImage(img));
  return Promise.all(tasks);
}
loadeImages(imgList).then(() => {
    // append to div
})
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题