十行代码手撸一个图片懒加载

181 阅读1分钟

先上代码


HTML

<img class="lazy-img" data-src="demo.jpg">

JavaScript

var lazyImgList = [].slice.call(document.querySelectorAll('.lazy-img'), 0);
function lazyload() {
    var viewHeight = window.innerHeight || document.documentElement.clientHeight; //可见区域高度
    lazyImgList = lazyImgList.filter(function (imgNode) {
        var imgRectTop = imgNode.getBoundingClientRect().top;
        if (imgRectTop <= viewHeight) {
            imgNode.src = imgNode.getAttribute("data-src");
            return false;
        }
        return true;
    });

    if (lazyImgList.length === 0) window.removeEventListener('scroll', lazyload);
}

lazyload();
window.addEventListener('scroll', lazyload);

原理

  • imgEl.getBoundingClientRect().top:是一个随滚动变化的值,是元素顶部距离视口顶部的距离;
  • window.innerHeight:浏览器窗口的视口(viewport)高度。

如图,当 imgEl.getBoundingClientRect().top <= window.innerHeight 时,元素进入视口,此时赋值图片的 src = data-src ,开始加载。

思考🤔

  • 使用 lazyImgList = lazyImgList.filter(···) 过滤掉已经加载过的图片。
  • imgRectTop - threshold <= viewHeight :可以添加一个阀值来控制图片出现在视口前加载,优化体验。
  • 如果需要对背景图进行懒加载,同样可以比较容器的DOMRect的top值与window.innerHeight的差值,来添加类名实现。(或通过js添加background-image)
  • <img src=···> 和背景图 代码解析到的时候都会发送资源请求,与display:none无关(可利用此特效实现预加载)。
  • window.innerHeight 不兼容 IE<9 的版本,使用 viewHeight = window.innerHeight || document.documentElement.clientHeight;
  • 根据需要对scroll事件进行节流。