图片懒加载

图片懒加载的集中实现方式

1.基于原生 js 实现图片懒加载

首先需要知道几个高度:

(1)document.documentElement.clientHeight

function getWindowHeight() {
            var windowHeight = 0;
            if (document.compatMode == "CSS1Compat") {
                windowHeight = document.documentElement.clientHeight;
            } else {
                windowHeight = document.body.clientHeight;
            }
            return windowHeight;
        }

获取屏幕可视区域的

(2)element.offsetTop

获取元素相对于文档顶部的高度。

(3)

document.documentElement.scrollTop

获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离。

然后滑动执行下面的方法:

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

        //offsetTop是元素与offsetParent的距离,循环获取直到页面顶部
        function getRealTop(e) {
            var realTop = e.offsetTop;
            while(e = e.offsetParent) {
                realTop += e.offsetTop;
            }
            return realTop;
        }

        function lazyLoad(imgs) {
            var H = document.documentElement.clientHeight;//获取可视区域高度
            var S = document.documentElement.scrollTop || document.body.scrollTop;
            for (var i = 0; i < imgs.length; i++) {
                if (H + S > getRealTop(imgs[i])) {
                    imgs[i].src = imgs[i].getAttribute('data-src');
                }
            }
        }

        window.onload = window.onscroll = function () { //onscroll()在滚动条滚动的时候触发
            lazyLoad(imgs);
        }

2.基于 getBoundingClientRect()实现图片懒加载

getBoundingClientRect()用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。getBoundingClientRect()DOM元素到浏览器可视范围的距离(不包含页面看不见的部分)。该函数返回一个rectObject对象,该对象有 6 个属性:topleftbottomrightwidthheight;这里的topleftcss中的理解很相似,widthheight是元素自身的宽高,但是rightbottomcss中的理解有点不一样。right是指元素右边界距窗口最左边的距离,bottom是指元素下边界距窗口最上面的距离。

通过这个 API,我们就很容易获取img元素相对于视口的顶点位置rectObject.top,只要这个值小于浏览器的高度window.innerHeight就说明进入可视区域:

function isInSight(el){
  const bound = el.getBoundingClientRect();
  const clientHeight = window.innerHeight;
  return bound.top <= clientHeight;
}

实现代码:

function loadImg(el){
 if(!el.src){
   const source = el.getAttribute('data-src');;
   el.src = source;
 }
}
function checkImgs(){
  const imgs = document.querySelectorAll('img');
  Array.from(imgs).forEach(el =>{
    if (isInSight(el)){
      loadImg(el);
    }
  })
}
window.onload = function(){
  checkImgs();
}
document.onscroll = function () {
  checkImgs();
}

3.基于 IntersectionObserver 实现图片懒加载

图片懒加载

我们在平时的开发中,常常需要了解某个元素是否进入了"视口"(viewport),即用户能不能看到它

上图的绿色方块不断滚动,顶部会提示它的可见性。

传统的实现方法是,监听到scroll事件后,调用目标元素(绿色方块)的getBoundingClientRect()方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于scroll事件密集发生,计算量很大,容易造成性能问题。

目前有一个新的 IntersectionObserver API,可以自动"观察"元素是否可见,Chrome 51+ 已经支持。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做交叉观察器

var io = new IntersectionObserver(callback, option);

上面代码中,IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。

构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点。

// 开始观察
io.observe(document.getElementById('container'));

// 停止观察
io.unobserve(element);

// 关闭观察器
io.disconnect();

上面代码中,observe的参数是一个 DOM 节点对象。

如果要观察多个节点,就要多次调用这个方法。

io.observe(elementA);
io.observe(elementB);

代码实现:

const imgs = document.querySelectorAll('img') //获取所有待观察的目标元素
var options = {}
function lazyLoad(target) {
  const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entrie => {
      if (entrie.isIntersecting) {
        const img = entrie.target;
        const src = img.getAttribute('data-src');
        img.setAttribute('src', src)
        observer.unobserve(img); // 停止监听已开始加载的图片
      }

    })
  }, options);
  observer.observe(target)
}

imgs.forEach(lazyLoad)

4.img.loading=lazy

最后这种相对就简单很多了,它是 Chrome 自带的原生 lazyload 属性。其实支持程度还不是特别好,我们你的应用对于浏览器兼容性要求比较高的话,建议还是先观望一波~

使用方法很简单:

<img src="example.jpg" loading="lazy" alt="">

 

上一篇:Javascript事件监听-回调函数-基础题


下一篇:C4JS学习