懒加载冰墩墩和雪绒容

210 阅读2分钟

懒加载冰墩墩和雪绒容

一、前言

不得不说,最近冰墩墩是一"墩"难求,作为我们的冬奥顶流,冰墩墩无疑是当下最大的热点,正好最近我也在学习关于前端优化的板块,今天我们就来一起看一下如何懒加载一个冰墩墩;

冰墩墩

二、背景

前端优化是一个非常重要的课题,而今天我们主要是来展示一下如何通过懒加载来减少首屏的压力;

众所周知,首屏加载资源的过程中,比如电商,那么多图片,那么多信息,都需要在用户打开时一下子展示出来;但实际上,用户往往看到的部分,并不是全部的内容,而是局部的内容,那是不是可以只展示用户视觉能够感知到的内容会更好一点呢,是的,这样的话,就可以减少首屏加载的压力!当用户触发诸如滚动的操作的时候,再展示用户想要看到的内容;实际上,这也是现如今大部分电商网站,尤其是手机端都在做的事情;

三、实践

我们今天使用一张冰墩墩和雪绒容的合照来作为目标图片加载;


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #container {
      width: 100vw;
      height: 100vh;
    }

    .img {
      width: 300px;
      height: 200px;
      border-radius: 8px;
      background: #eee;
      margin: 10px auto;
    }

    img {
      width: 100%;
      height: 100%;
    }
  </style>
</head>

<body>
  <div id="container">
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
    <div class="img">
      <img data-src="./imgs/bingdundun.jpeg">
    </div>
  </div>
</body>

</html>

以上是html的部分;使用一个阴影图片进行展位;将实际的资源路径挂在到dom上;这里的css有一个小技巧,因为如何img标签没有src属性,会有一个非border的边框;如下图所示;

截屏2022-02-07 下午9.44.30.png 所以我们加一个样式


img:not([src]) {
  opacity: 0;
}

对于没有src属性的,我们统一使其透明度变为0,之后使用js动态添加src,那么该样式就不生效了,图片就加载出来了;我们先看一下效果图;

截屏2022-02-07 下午9.51.01.png

接下来是js的部分;是这样设想的;对于处于视口的内容,我们让其加载,对于不处于视口的不让加载;


let imgs = document.getElementsByTagName("img");
function addBackground(dom) {
  dom.src = dom.dataset.src;
}

function checkAndAddBackground() {
  let viewHeight = window.innerHeight;
  Array.from(imgs).forEach(img => {
    if (!img.src) {
      let top = img.getBoundingClientRect().top;
      if (top <= viewHeight) {
        addBackground(img)
      }
    }
  });
}

先定义两个函数;一个用于将指定的img添加上src,另一个是检查每一个img,如果已加载,忽略,如果未加载,那么就判断是否在视口内,只有在视口内的才进行加载;否则忽略;

看是否在视口,使用的是一个getBoundingClientRect的api;它的使用形如下图;


function main() {
  checkAndAddBackground();
  let container = document.createElement("container");
  window.addEventListener("scroll", checkAndAddBackground)
}

main()  // 调用主函数;

上面的代码添加上之后,其实就可以完成懒加载的效果了,但是特别不好;因为checkAndBackground触发的频率太高;我们需要使用防抖函数进行一个优化;


function debounce(func, delay) {
  let timer = null;
  return function (args) {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      func.apply(this, args)
    }, delay);
  }
}


function main() {
  checkAndAddBackground();
  let container = document.createElement("container");
  let listenScroll = debounce(checkAndAddBackground, 500);
  window.addEventListener("scroll", listenScroll)
}

main();

通过上面的优化我们现在来看一下效果;

1644242982842.gif