实现图片懒加载的三种方式,你确定都知道吗!!

415 阅读3分钟

介绍

所谓的图片懒(延迟)加载就是指图片出现在我们的视口(viewport)内才进行加载,这样可以有效的减轻服务器压力和节省流量。

想想,如果一个长列表页面,共有100张图片,但是我们首先看到的只有视口内前几张,那么视口以下的图片我们可能并没有看到,这样如果全都下载,那么就是一种资源的浪费,增加服务器压力,同时也浪费流量。

如何实现

这里教给大家三种方式来实现:

  1. 传统的 el.offsetTop < clientHeight + scrollTop位置来判断
  2. Element.getBoundingClientRect():此方法返回元素的大小及其相对于视口的位置
  3. IntersectionObserver():提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。此种效率是最高的。

方式一实现: offsetTop

原理图:

image.png

页面布局结构

<body>
    <p>111111111111111111</p>
    <p>111111111111111111</p>
    <p>111111111111111111</p>
    <p>111111111111111111</p>
    <p>111111111111111111</p>
    <p>111111111111111111</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <p>2222222222222222</p>
    <img width="200px" data-src="https://img0.baidu.com/it/u=593652383,3007722262&fm=26&fmt=auto&gp=0.jpg" alt="">  <br />

    <img width="200px" data-src="https://img1.baidu.com/it/u=2247241615,3725296843&fm=26&fmt=auto&gp=0.jpg" alt=""> <br /> 
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <h3>3333333333333333333</h3>
    <img id="imgabc" width="200px" data-src="https://img0.baidu.com/it/u=2658555271,1114326008&fm=26&fmt=auto&gp=0.jpg" alt="">
    <br />
    
    <h3>44444444444</h3>
    <h3>44444444444</h3>
    <h3>44444444444</h3>
    <h3>44444444444</h3>
    <h3>44444444444</h3>
</body>

js:

<script>
  
    let imgs = document.querySelectorAll('img');
    
    function scrollHandle(imgs){
        let pageScrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
        // 或 window.innerHeight
        let clientHeight = document.documentElement.clientHeight;
        imgs.forEach(img => {
            let offsetTop = img.offsetTop;
            let done = img.getAttribute('loaded');
            // 提前50像素预加载
            if(offsetTop - 50 <  pageScrollTop + clientHeight){
                !done && (img.src = img.getAttribute('data-src')) && img.setAttribute('loaded', 'done')
            }
        })
    }

    window.onscroll = function(event){
        scrollHandle(imgs)
    };

    // 初始化一次 immediate
    scrollHandle(imgs)
   

</script>

打开浏览器体验吧!!

方式二:getBoundingClientRect

Element.getBoundingClientRect():此方法返回元素的大小及其相对于视口的位置

原理:

image.png

<script>
    let imgs = document.querySelectorAll('img');
    let windonHeight = window.innerHeight;
    console.log(windonHeight);

    window.onscroll = function () {
        imgs.forEach(img => {
            if (img.getAttribute('isDone')) {
                return;
            }
            let top = img.getBoundingClientRect().top;
            if (top > 0 && top < windonHeight) {
                console.log('jiazai ');
                img.src = img.getAttribute('data-src');
                img.setAttribute('isDone', true)
            }
        })
    }
</script>

方式三: IntersectionObserver

IntersectionObserver():提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。此种效率是最高的。

<script>

    let imgs = document.querySelectorAll('img');
    let observer = new  IntersectionObserver((entries)=>{
        // 观察所有
        entries.forEach( entry => {
            if(entry.isIntersecting){
                const image = entry.target;
                image.src = image.getAttribute('data-src');
                console.log('requesting')
                // 取消观察
                observer.unobserve(image)
            }
        } )
    })
    imgs.forEach(img => {
        observer.observe(img)
    })

</script>

有名的Vue-lazyload模块底层也采用了IntersectionObserver方案来实现。

效果:

image.png

注意:此方式IE不兼容