js实现图片懒加载

220 阅读1分钟

如果一个页面图片过多,则需要一次性请求所有图片。对于用户侧来说,会浪费大量的流量去下载可能不需要的图片,对于服务端来说,则会占用大量的带宽。

一、原理

图片.png 浏览器通过img的src属性来判断是否发起请求,当图片进入浏览器可视区域时,用js取到该图片的data-src的值赋给src。

二、实现

1、因为需要在scroll中来去判断是否在视口内,但是scroll触发非常频繁,因此需要结合节流来去实现。节流代码:

function throttle(fn, delay) {
    let valid = true;
    return function() {
        if (!valid) {
            return false;
        }
        valid = false;
        setTimeout(() => {
            fn();
            valid = true;
        }, delay);
    }
}

2、判断是否处于视口之内

Element.getBoundingClientRect()方法返回一个 DOMRect对象,其提供了元素的大小及其相对于视口的位置。

返回值是一个 DOMRect对象,是包含整个元素的最小矩形(包括padding 和border-width )。该对象使用left 、top 、 right、 bottom 、x 、y、width 和height这几个以像素为单位的只读属性描述整个矩形的位置和大小。除了width和 height以外的属性是相对于视图窗口的左上角来计算的。

图片.png

function isElementInViewport (el) {
  const { left, top } = el.getBoundingClientRect();
  const viewportW = window.innerWidth || document.body.clientWidth;
  const viewportH = window.innerHeight || document.body.clientHeight;
  return top <= viewportH && left <= viewportW;
}

3、实现

因为scroll只有当滚动的时候才会触发,因此需要先加载首屏的图片

const imgs = document.querySelectorAll('img');

function lazyLoad(imgs) {
  let currentIndex = 0;

  function loadImg() {
    while (currenIndex < imgs.length) {
      const img = imgs[currentIndex];

      if (isElementInViewport(img)) {
        const src = img.getAttribute('data-src');
        img.src = src;
        currenIndex++;
      } else {
        break;
      }
    }
  }

  loadImg();
  return loadImg;
}


window.onload = function() {
  window.addEventListener('scroll', throttle(lazyLoad(imgs), 200));
}