图片懒加载,原理你可一定要会

目录

前言:

懒加载是什么?

基础知识

实现方式

(一)监听scroll事件

(二)IntersectionObserver

(三)img标签添加属性loading="lazy"


前言:

面试时碰到了这个问题,之前练手项目的时候用过,但没有深入了解其底层原理,所以面试结果应该只能唱一首凉凉了,现做一个总结,后面继续加油,也希望大家吸取教训

懒加载是什么?

懒加载肯定重点突出一个‘懒’字,我们来从发现什么问题,然后怎么解决去解决的角度来看

首先是有什么问题呢?在我们访问一个图片展示比较多的网页时,加载速度慢很多时候正是因为图片多导致,大量的img图片导致页面渲染的堵塞。当费了许多力气把全部图片和页面加载出来时而用户早已离去。另一方面,若用户只查看了网页的前面部分便离开,许多已经加载却因为处于网页底部而未呈现在视口区的图片,它们极大加重服务器压力了但是用户看都没看,白白浪费了性能。

为了解决上面的问题需要引入图片懒加载,当用户滚动相应可视区域,若可视区域有图片便加载,而在可视区域外未加载过的图片它们先不加载,如果用户滚动可视区域到它们时它们再加载,否则一律不加载。这样一来就大大提高了网页渲染的性能和减少不必要的浪费。

基础知识

如何判断元素是否到达可视区域
  • window.innerHeight 是浏览器可视区的高度;
  • document.body.scrollTop || document.documentElement.scrollTop是浏览器滚动的过的距离;
  • imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离);
  • 内容达到显示区域的: img.offsetTop < window.innerHeight + document.body.scrollTop;

实现方式

实现图片的懒加载有两个思路:

  • 事件监听:监听scroll事件,鼠标滚动就触发
  • IntersectionObserver:按字面意思就是交叉观察,也就是目标元素和可视窗口会产生交叉区域,观察交叉区域发生什么事情,执行什么程序

IntersectionObserver

IntersectionObserver接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。

Intersection Observer可以不用监听scroll事件,做到元素一可见便调用回调,在回调里面我们来判断元素是否可见。

(一)监听scroll事件

就像我们上面的基础知识所说的,可以用img.offsetTop < window.innerHeight + document.body.scrollTop;判断图片是否到达可视区域

不过这个方案有个很大的问题,就是会多次触发,最好和节流一起使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片懒加载方法一</title>
    <style>
        img{
            width: 1244px;
            height: 800px;
        }
    </style>
</head>

<body>
    <h3>图片懒加载方法一</h3>
    <!-- 图片,用一个其他属性存储真正的图片地址: -->
    <img data-src="img/1.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/2.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/3.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/4.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/5.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/6.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/7.webp" src="img/0.webp" alt="xxx" />

    <script>
        const images = document.querySelectorAll("img");
        // lazyload(); //页面载入完毕加载可视区域内的图片 要看效果的话还是不加比较好
        // 节流函数,保证每200ms触发一次
        function throttle(fn, delay) {
            let timer = null
            return function (...args) {
                if (!timer) {
                    timer = setTimeout(() => {
                        timer = null
                        fn.apply(this, args)
                    }, delay)
                }
            }
        }
        window.addEventListener('scroll', throttle(lazyload, 500))
        function lazyload() { //监听页面滚动事件
            var seeHeight = window.innerHeight; //可见区域高度
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滚动条距离顶部高度
            for (let i of images) {
                //判断当前图片是否在可视区内
                if (i.offsetTop <= seeHeight+scrollTop) {
                    //getAttribute得到某个元素的属性值,获取自定义data-src属性的值
                    let trueSrc = i.getAttribute("data-src");
                    //setAttribute设置某个属性的属性值,把值赋值给图片的src属性
                    i.setAttribute("src", trueSrc);
                }
            }
            // for (let i of images) {
            //     //计算方式和第一种方式不同
            //     if (i.getBoundingClientRect().top < window.innerHeight) {
            //         let trueSrc = i.getAttribute("data-src");
            //         i.setAttribute("src", trueSrc);
            //     }
            // }    其中,getBoundingClientRect().top 为元素相对于窗口的位置;window.innerHeight 为当前窗口的高度;
            // 当元素对于窗口的位置小于当前窗口的高度时,那自然处于了窗口可视区了。
        }

    </script>
</body>

</html>

(二)IntersectionObserver

当一个IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦IntersectionObserver被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片懒加载方法一</title>
    <style>
        img {
            width: 1244px;
            height: 800px;
        }
    </style>
</head>

<body>
    <h3>图片懒加载方法一</h3>
    <!-- 图片,用一个其他属性存储真正的图片地址: -->
    <img data-src="img/1.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/2.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/3.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/4.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/5.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/6.webp" src="img/0.webp" alt="xxx" />
    <img data-src="img/7.webp" src="img/0.webp" alt="xxx" />

    <script>
        const images = document.querySelectorAll("img");

        // 传给IntersectionObserver的回调函数
        // 在目标元素能看见时触发一次,目标元素看不见了时再触发一次
        const observer = new IntersectionObserver(entries => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const image = entry.target;
                    const data_src = image.getAttribute("data-src");
                    image.setAttribute("src", data_src);
                    // 图片被加载后取消观察
                    observer.unobserve(image);
                }
            });
        });

        images.forEach(image => {
            observer.observe(image);
        });


    </script>
</body>

</html>

(三)<img/>标签添加属性loading="lazy"

chrome支持,其他浏览器暂时不支持

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片懒加载方法二</title>
    <style>
        img {
            width: 1244px;
            height: 800px;
        }
    </style>
</head>

<body>
    <h3>图片懒加载方法三</h3>
    <!-- 图片,用一个其他属性存储真正的图片地址: -->
    <img src="img/1.webp" alt="xxx" loading="lazy"/>
    <img src="img/2.webp" alt="xxx" loading="lazy"/>
    <img src="img/3.webp" alt="xxx" loading="lazy"/>
    <img src="img/4.webp" alt="xxx" loading="lazy"/>
    <img src="img/5.webp" alt="xxx" loading="lazy"/>
    <img src="img/6.webp" alt="xxx" loading="lazy"/>
    <img src="img/7.webp" alt="xxx" loading="lazy"/>

   
</body>

</html>

上述讲解代码可以从https://github.com/guodongO/example下载

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值