图片懒加载的原理

549 阅读2分钟

这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。

实现效果

先来描述下图片懒加载实现的一个效果,就是当图片出现在可视区域是再去加载图片资源,初始的时候可以默认设置一个loading图。
为什么需要懒加载呢? 比如像淘宝京东这种购物网站一样,一个页面有很多图片,如果一次加载出来,那加载速度不敢想象。
这时采用懒加载,也就是说优先加载用户所能看到区域内的图片,其他的不展示也就先搁置,一次性加载100张图片跟一次性加载10张图片,其差距不言而喻。

图片懒加载的好处

  • 提高用户体验 现在做什么都要考虑用户体验,一进页面就要看着卡顿的页面等待图片加载,还是进入页面就能快速的看到想看的画面,如果你是用户你会用哪一个?

  • 减少http请求 一次加载1000张图,还是一次性加载10张图,哪个好,要你选?

  • 减轻服务器端压力 加载图片多,网站也不可能只有一个人用。

总之,懒加载能防止页面一次性向服务器响应大量请求导致服务器响应慢,页面卡顿或崩溃等问题。

实现原理

图片展示就是用的标签,浏览器根据img的src属性去加载图片,所以实现懒加载的关键就是,当图片没有进入可视区域时,先不给src属性赋值,这样浏览器就不会发送请求,等图片进入可视区域再赋值。

具体实现

  • 初始可以给图片加一个默认的loading图
  • 自定义一个data-src属性来存储图片的真实地址
  • 判断图片是否在可视区域,如何判断?
  • 图片在可视区域时,设置src属性为真正要加载的地址

demo

先来看一张图,些许潦草了

image.png

图片标注了一些文档元素属性:

  • document.documentElement.scrollHeight(文档内容实际高度,包括不可见区域
  • document.documentElement.scrollTop(滚动条滚动距离)
  • document.documentElement.clientHeight(文档可视范围高度)
  • document.documentElement.offsetHeight (元素偏移高度,包括边界线border) 浏览器可视区域
  • window.innerWidth (浏览器窗口宽度,不包含工具栏,菜单等,仅仅是可视区域dom的width)
  • window.innerHeight (浏览器窗口高度,不包含工具栏,菜单等,仅仅是可视区域dom的height)
  • window.outerWidth (浏览器窗口宽度,包含工具栏、菜单等,整个浏览器的width)
  • window.outerHeight (浏览器窗口高度,包含工具栏、菜单等,整个浏览器的height)
<!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>
</head>
<body>
    <div>
        <img src="./img/loading.gif" data-src='./img/img1.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img2.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img3.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img4.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img5.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img6.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img7.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img8.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img9.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img10.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img11.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img12.jpeg' alt="">
        <img src="./img/loading.gif" data-src='./img/img13.jpeg' alt="">
    </div>
</body>
<script>
    (function(){
        var imgs = document.getElementsByTagName('img')
        console.log(imgs)
        function lazyLoad(imgs) {
            //window.innerHeight一样的
            var h = document.documentElement.clientHeight;
            var s = document.documentElement.scrollTop || document.body.scrollTop;
            for(let i = 0; i < imgs.length; i++){
                // 如果图片距离顶部的距离 小于 滚动区域与可视区域之和时,加载图片
                if((h + s) > imgs[i].offsetTop) {
                    // 替换真实图片
                    imgs[i].src = imgs[i].getAttribute('data-src')
                }
            }
        }
        lazyLoad(imgs);
        // 监听页面滚动
        window.onscroll = function (){
            lazyLoad(imgs)
        }
    })()
</script>
</html>

替换成功的 image.png