乐趣区

关于前端:手摸手教你实现图片懒加载

懒加载(Lazy-Load)。它是针对图片加载机会的优化:在一些图片量比拟大的网站(比方电商网站首页,或者团购网站、小游戏首页等),如果咱们尝试在用户关上页面的时候,就把所有的图片资源加载结束,那么很可能会造成白屏、卡顿等景象,因为图片真的太多了,一口气解决这么多任务,浏览器做不到啊!

目标

懒加载 的目标是当页面的图片进入到用户的可视范畴之内在加载图片的一种优化形式。

能够减少首屏加载的速度,毕竟,用户点开页面的霎时,出现给他的只是首屏,咱们只有把首屏的资源图片加载解决就能够了,至于上面的图片,当用户下滑当以后地位的时候,在加载进去也是没问题的,对于性能压力也小了,用户体验也没有变差。

原理

在页面初始化的时候,
<img>图片的 src 实际上是放在 data-src 属性上的,当元素处于可视范畴内的时候,就把 data-src 赋值给 src 属性,实现图片加载。

// 在一开始加载的时候
<img data-src="http://xx.com/xx.png" src="" />

// 在进入可视范畴内时
<img data-src="http://xx.com/xx.png" src="http://xx.com/xx.png" />

<div> 应用背景图来实现,原理也是一样的,把 background-image 放在,在可视范畴时,就把 data-src 赋值给 src 属性,实现图片加载。

// 在一开始加载的时候
<div
  data-src="http://xx.com/xx.png"
  style="background-image: none;background-size: cover;"
></div>

// 在进入可视范畴内时
<div
  data-src="http://xx.com/xx.png"
  style="background-image: url(http://xx.com/xx.png);background-size: cover;"
></div>

实现一个懒加载

基于下面的实现思路,本人实现一个懒加载。

新建一个 index.html 中,为这些图片预置 img 标签:

<head>
  <style>
    .img {
      width: 200px;
      height: 200px;
      background-color: gray;
      margin-bottom: 20px;
    }

    .pic {
      width: 100%;
      height: 100%;
    }
  </style>
</head>
<!-- 图片来自网络,侵删。-->

<body>
  <div class="container">
    <div class="img">
      <!-- 留神咱们并没有为它引入实在的 src -->
      <img
        class="pic"
        alt="加载中"
        data-src="https://tse1-mm.cn.bing.net/th/id/OIP.8OrEFn_rKe82kqAWFjTuMwHaEo?pid=Api&rs=1"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://ssl.tzoo-img.com/images/tzoo.94911.0.910013.seoul-nami.jpg?width=1080"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://tse4-mm.cn.bing.net/th/id/OIP.ZitgAuABnwkrGn4lid2ZmQHaEK?pid=Api&rs=1"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="http://pic34.photophoto.cn/20150315/0034034862056002_b.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="http://img.mp.sohu.com/upload/20170724/32d4409f34194b029ed287abf1c99b70_th.png"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://pic6.wed114.cn/20180829/2018082910075991913520.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://tse4-mm.cn.bing.net/th/id/OIP.PZdPKj3sXEX2jLrepx3MUwHaEo?pid=Api&rs=1"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://pic6.wed114.cn/20180829/2018082910075831439349.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://pic6.wed114.cn/20180829/2018082910075468043336.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加载中"
        data-src="https://tse2-mm.cn.bing.net/th/id/OIP.CRYz5Bv4vylsMh83G4CsLgHaFj?pid=Api&rs=1"
      />
    </div>
  </div>
</body>

在懒加载的实现中,有两个要害的数值:一个是 以后可视区域的高度 ,另一个是 元素间隔可视区域顶部的高度

以后可视区域的高度 ,在古代浏览器及 IE9 以上的浏览器中,能够应用window.innerHeight 属性获取,在低版本的 IE 中应用document.documentElment.clientHeight 获取,这里咱们兼容两种状况:

const viewHeight = window.innerHeight || document.documentElement.clientHeight;

元素间隔可视区域顶部的高度 ,这里咱们用 getBoundingClientRect() 办法来获取返回元素的大小和绝对于尺寸的地位,对于该 API,MDN 的解释是:

Element.getBoundingClientRect() 办法返回元素的大小及其绝对于视口的地位。

返回的属性中有一个绝对于可视区域顶部的高度也就是 top 属性,刚好就是咱们须要的元素间隔顶部的间隔。

这样,两个属性就都失去了。

咱们利用 以后可视区域的高度 大于等于 元素间隔可视区域顶部的高度 就能够确定,该元素是否曾经进入到了可视范畴:

<script>
  // 获取所有的图片标签
  const imgs = document.getElementsByTagName("img");
  // 获取可视区域的高度
  const viewHeight =
    window.innerHeight || document.documentElement.clientHeight;
  // num 用于统计以后显示到了哪一张图片,防止每次都从第一张图片开始查看是否露出
  let num = 0;

  function lazyload() {console.log("滚动...");
    for (let i = num; i < imgs.length; i++) {
      // 用可视区域高度减去元素顶部间隔可视区域顶部的高度
      let distance = viewHeight - imgs[i].getBoundingClientRect().top;
      // 如果可视区域高度大于等于元素顶部间隔可视区域顶部的高度,阐明元素露出
      if (distance >= 0) {
        // 给元素写入实在的 src,展现图片
        imgs[i].src = imgs[i].getAttribute("data-src");
        // 前 i 张图片曾经加载结束,下次从第 i + 1 张开始查看是否露出
        num = i + 1;
      }
    }
  }

  // 防抖函数
  function debounce(fn, delay = 500) {
    let timer = null;
    return function (...args) {if (timer) clearTimeout(timer);
      timer = setTimeout(() => {fn.call(this, args);
      }, delay);
    };
  }

  // 是的页面初始化是加载首屏图片
  window.onload = lazyload;
  // 监听 Scroll 事件,为了避免频繁调用,应用防抖函数优化一下
  window.addEventListener("scroll", debounce(lazyload, 600), false);
</script>
  • 图片懒加载 - 线上预览

小结

  1. 先收集到页面中所有的img(也能够用class)。
  2. 获取到视图高度,计算显示的img,防止反复赋值src
  3. 当滑动向下滑动鼠标,会触发 onScroll 事件(防抖),而后触发计算是否赋值src

参考资料

  • 修言 - 前端性能优化原理与实际小册
退出移动版