阅读 1672
原生JS实现图片懒加载

原生JS实现图片懒加载

图片懒加载是一种网页性能优化的方式,它能极大的提高用户体验。同时在面试的时候也经常容易被面试官问到其实现和原理,很早之前就接触过,由于最近几个月都没有写文章了,想着借此机会顺便复习一下

为什么需要懒加载?

在一些图片比较多的网站(比如说大型电商网站)图片是非常多的,如果我们在打开网页的一瞬间就把网站的所有图片加载出来,很有可能造成卡顿和白屏的现象,用户体验变得极其的差,要是遇到脾气暴躁的小伙伴相信直接反手就是一个Ctrl+W。
因为图片真的很多,一瞬间就把网站的所有图片加载出来浏览器短时间内根本处理不完,但是我们打开网站的那一瞬间仅仅只能看到视口内的图片,这时候去加载网页最底部的图片是非常浪费资源和没有必要的,所以遇到这种情况使用懒加载技术就显得尤为必要了。

懒加载实现原理

懒加载的原理其实很简单,就是预先将图片真实的src放在我们自定义的属性里面(比如data-src),当图片出现在了我们的视口范围之内的时候,再把data-src赋值给src属性,完成图片加载。

// 页面初始化时
<img data-src="https://img11.360buyimg.com/pop/s590x470.jpg.webp" />

// 当图片出现在了视口范围之内
<img data-src="https://img11.360buyimg.com/pop/s590x470.jpg.webp" src="https://img11.360buyimg.com/pop/s590x470.jpg.webp"/>
复制代码

这里有个点就是初始化时可以不给img标签加上src属性,因为只要存在src属性,浏览器就会去执行一次请求将其指向的资源下载并应用到文档内,这里不加上可以提升一些性能

具体实现

基于前面讲解的思路,我们自己手写一个懒加载

新建一个lazyload.html文件,初始化dom结构并设置对应的样式

<!DOCTYPE html>
<html>
<head>
  <title>lazy load</title>
  <style>
    .img {
      width: 220px;
      height: 220px;
      background-color: #ccc;
      margin-bottom: 40px;
      margin-left: 50px;
    }

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

<body>
  <div class="container">
  <!--将真实的src先放在data-src中-->
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img10.360buyimg.com/n7/jfs/t1/183679/11/2189/143829/6091f5d8E933e7ad1/e3e2001666f2ce7b.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img12.360buyimg.com/n7/jfs/t1/192682/11/617/163213/608b887aEddbbbee3/9570466a90d02f79.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img14.360buyimg.com/n7/jfs/t1/156161/35/18802/268242/60641d96Eca3dee7f/4a32070a19deb4f5.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img10.360buyimg.com/n7/jfs/t1/130179/12/9273/167054/5f5468edE9d4ecd9c/39f7520d9f76b695.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img14.360buyimg.com/n7/jfs/t1/100888/13/13132/105320/5e5533c6Ea8daa487/f95d7ba4da5581c5.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img10.360buyimg.com/n7/jfs/t1/173986/31/8862/291849/6098d6d0E26c55012/c2144f6e074556d2.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img10.360buyimg.com/n7/jfs/t1/110754/4/12605/101916/5ee43244E6fbf9433/c42fb5e3f9558a59.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img10.360buyimg.com/n7/jfs/t1/148370/31/1084/45848/5eedc2eeEfdc2cd46/f3c3a6f0bd7998be.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img10.360buyimg.com/n7/jfs/t1/165930/8/7273/171076/602fd5dfE65a52775/ee27074b7037c020.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img13.360buyimg.com/n7/jfs/t1/190093/28/117/193777/60867822Ea949fbec/6fe51b122d0fdc5a.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="加载中..." data-src="https://img14.360buyimg.com/n7/jfs/t1/119501/15/6768/115886/5eca6c36Eb3541dc9/2f4534173878a23c.jpg" />
    </div>
  </div>
  </body>
  </html>
复制代码

接下来是JS部分,我们需要提前知道几个值,一个是当前浏览器窗口的视口高度,另一个是每张图片距离视口顶部的距离,因为只有当图片距离顶部的距离小于我们的视口高度,那么就代表这张图片已经出现在我们的视口范围内了。

获取浏览器视口高度

获取可视区域的高度我们通常使用window.innerHeight就可以拿到了,当然如果需要兼容低版本IE浏览器的话则可以使用document.documentElement.clientHeight来获取,这里我们做一个兼容处理

const viewPortHeight = window.innerHeight || document.documentElement.clientHeight
复制代码

获取图片离顶部的距离

这里我们简单粗暴一点,直接使用getBoundingClientRect()这个方法来获取,对这个方法不了解的小伙伴可以点击这里进行查看

到这里,我们所需要的两个值就都可以拿到了,下面直接上代码:

// 获取所有图片
const imgList = document.querySelectorAll('img')
// 用于记录当前显示到了哪一张图片
let index = 0;
function lazyload() {
  // 获取浏览器视口高度,这里写在函数内部是考虑浏览器窗口大小改变的情况
  const viewPortHeight = window.innerHeight || document.documentElement.clientHeight
  for (let i = index; i < imgList.length; i++) {
    // 这里用可视区域高度减去图片顶部距离可视区域顶部的高度
    const distance = viewPortHeight - imgList[i].getBoundingClientRect().top;
    // 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明图片已经出现在了视口范围内
    if (distance >= 0) {
      // 给图片赋值真实的src,展示图片
      imgList[i].src = imgList[i].getAttribute('data-src');
      // 前i张图片已经加载完毕,下次从第i+1张开始检查是否需要显示
      index = i + 1;
    }
  }
}

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

// 页面加载完成执行一次lazyload,渲染第一次打开的网页视口内的图片
window.onload = lazyload;
// 监听Scroll事件,为了防止频繁调用,使用防抖函数进行优化
window.addEventListener("scroll", debounce(lazyload, 600));
// 浏览器窗口大小改变时重新计算
window.addEventListener("resize", debounce(lazyload, 600));

复制代码

最后效果

到这里我们的图片懒加载就写完了,下面是效果图,喜欢的朋友麻烦点个赞吧

collapse.gif

文章分类
前端
文章标签