图片懒加载和节流

192 阅读3分钟

当一个页面需要展示很多图片的时候, 如果不使用懒加载技术, 一次性加载成百上千的图片的时候, 可能会出现下面的图片加载完了, 但是可视区域的图片却还在加载中, 造成极其不好的体验. 因为浏览器对一个域名的请求数量是有限制的, chrom是一次最多加载6张图片, 超过这个数量, 其他图片就会进入请求队列. 只有前面的加载完, 后面的才能继续加载.

节流

为什么要了解节流的思想? 因为图片懒加载是在鼠标滚轮滚动的时候触发, 如果不加限制, 那么当用户滚动比较快的时候, 一次性加载图片也是巨量的, 会导致懒加载看不出效果来.

节流就是在n秒内触发的同一个事件会被忽略掉, 只会在停下触发n秒后才会执行

鼠标滚轮触发是非常频繁的, 可能滚动一次可能会触发几十上百次. 使用节流的话, 只会触发一次.

  throttle(func, wait) {
    // func - 滚轮事件的处理函数
    // wait - 间隔秒数, 连续触发的两次事件间隔小于这个事件都会被忽略掉, 只会执行最后一次
    let timeout;
    let startTime = new Date();
    return function(e) {
      var context = this,
        args = arguments,
        curTime = new Date();
      clearTimeout(timeout);
      timeout = setTimeout(func, wait);
    };
  }

这里实际使用的是一个闭包的思想, 在wait毫秒内触发的事件, 都会把这个一次性定时器清除掉. 并重新创建一个wait毫秒的定时器. 只有触发事件间隔大于wait秒, 才会执行func函数

懒加载思想

懒加载主要是处理鼠标滚动到指定位置的时候, 可视区域能看到想要看的图片.

比如有这么一段html代码:

<div id="lazy-load" class="img-con">
  <span class="img-item">
    <img src="empty.png" data-mid="1" alt="">
  </span>
</div>

这里 .img-con 表示图片容器的div, .img-item是单个图片的容器 为啥要在img标签外面包一层span, 因为没包被坑过不少次, 包一层以后修改样式啥的, 会更方便点, 包一层能解决很多问题. 经验之谈.

懒加载js处理部分

document.getElementById('lazy-load').addEventListener('scroll', throttle(imgLazyLoad, 30, 300), true);

imgLazyLoad = (data=[]) => {
  // data: 对象数组, {mid: '', imgSrc: '图片地址'}每个对象里面有一个图片地址属性

  // 修改判断逻辑,从可见部分开始加载
  // pic - 图片模式 , list - 列表模式
  let imgCon = null;
  // 获取图片容器的位置信息和尺寸信息
  imgCon = document.querySelector('.img-con');
  if (imgCon) {
    const imgs = imgCon.querySelectorAll('img');
    if (imgs) {
      // 获取mid对应的真实图片路径
      const relImgs = {};
      for (let i=0; i<data.length; i++) {
        const item1 = data[i];
        relImgs[item1.mid] = item1.imgSrc;
      }
      // 获取图片的位置信息和尺寸信息
      const conElInfo = imgCon.getBoundingClientRect();
      for (let i=0; i<imgs.length; i++) {
        const item = imgs[i];
        const curMid = item.getAttribute('data-mid');
        const curInfo = item.getBoundingClientRect();
        // 核心处理: 判断当前图片是否在可视区域内
        if ((curInfo.top+curInfo.height) - conElInfo.top > 0) {
          // 校验图片地址真实存在
          if (relImgs[curMid] && relImgs[curMid]!=='') {
            // 当前图片如果是一张占位图, 则加载真实图片, 否则认为该图片已经加载好了
            if(item.src.indexOf('empty.png')!==-1) {
              item.src = relImgs[curMid];
            }
          }
        }
      }
    }
  }
}

这里面的核心思路就是判断当前图片是否在可视区域内 (curInfo.top+curInfo.height) - conElInfo.top > 0: curInfo.top+curInfo.height: 图片底部距离页面顶部的距离 conElInfo.top: 图片容器距离页面顶部的距离 (curInfo.top+curInfo.height) - conElInfo.top: 判断元素是否在图片容器可视区内

总结

图片懒加载技术的核心就是节流思想和位置判断, 掌握这两个思路了, 其它可以自己调整, 这里的节流我也没用完整, 把不需要的部分截取掉了, 不用多少时间内一定加载一次. 更加适合我做的项目.