图片懒加载的三种方式

方法一:滚动监听 + scrollTop + offsetTop + innerHeight

scrollTop:指网页元素被滚动条卷去的部分。

offsetTop:元素相对父元素的位置

innerHeight:当前浏览器窗口的大小。需要注意兼容性问题。

html 复制代码
<!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>Document</title>
    <style>
        img {
            background: url('./img/loading.gif') no-repeat center;
            width: 250px;
            height: 250px;
            display: block;
        }
    </style>
</head>

<body>
    <img src="./img/pixel.gif" data-url="./img/1.jpeg">
    <img src="./img/pixel.gif" data-url="./img/2.jfif">
    <img src="./img/pixel.gif" data-url="./img/3.jfif">
    <img src="./img/pixel.gif" data-url="./img/4.jfif">
    <img src="./img/pixel.gif" data-url="./img/5.jfif">
    <img src="./img/pixel.gif" data-url="./img/6.webp">

    <script>

        let imgs = document.getElementsByTagName('img')
        // 1. 一上来立即执行一次
        fn()
        // 2. 监听滚动事件
        window.onscroll = lazyload(fn, true)
        function fn() {
            // 获取视口高度和内容的偏移量
            let clietH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
            var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            console.log(clietH, scrollTop);
            for (let i = 0; i < imgs.length; i++) {
                let x = scrollTop + clietH - imgs[i].offsetTop //当内容的偏移量+视口高度>图片距离内容顶部的偏移量时,说明图片在视口内
                if (x > 0) {
                    imgs[i].src = imgs[i].getAttribute('data-url'); //从dataurl中取出真实的图片地址赋值给url
                }
            }
        }
          // 函数节流
        function lazyload(fn, immediate) {
            let timer = null
            return function () {
                let context = this;
                if (!timer) {
                    timer = setTimeout(() => {
                        fn.apply(this)
                        timer = null
                    }, 200)
                }
            }
        }


    </script>
</body>

</html>

方法二:滚动监听 + getBoundingClientRect()

rectObject.top:元素上边到视窗上边的距离;

rectObject.right:元素右边到视窗左边的距离;

rectObject.bottom:元素下边到视窗上边的距离;

rectObject.left:元素左边到视窗左边的距离;

rectObject.width:元素自身的宽度;

rectObject.height:元素自身的高度;

html 复制代码
<!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>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        img {
            background: url('./img/loading.gif') no-repeat center;
            width: 250px;
            height: 250px;
            display: block;
        }
    </style>
</head>

<body>
    <img src="./img/pixel.gif" data-url="./img/1.jpeg">
    <img src="./img/pixel.gif" data-url="./img/2.jfif">
    <img src="./img/pixel.gif" data-url="./img/3.jfif">
    <img src="./img/pixel.gif" data-url="./img/4.jfif">
    <img src="./img/pixel.gif" data-url="./img/5.jfif">
    <img src="./img/pixel.gif" data-url="./img/6.webp">

    <script>

        let imgs = document.getElementsByTagName('img')
        // 1. 一上来立即执行一次
        fn()
        // 2. 监听滚动事件
        window.onscroll = lazyload(fn, true)
        function fn() {
            // 获取视口高度和内容的偏移量
            let offsetHeight = window.innerHeight || document.documentElement.clientHeight
            Array.from(imgs).forEach((item, index) => {
                let oBounding = item.getBoundingClientRect() //返回一个矩形对象,包含上下左右的偏移值
                console.log(index, oBounding.top, offsetHeight);
                if (0 <= oBounding.top && oBounding.top <= offsetHeight) {
                    item.setAttribute('src', item.getAttribute('data-url'))
                }
            })
        }
        // 函数节流
        function lazyload(fn, immediate) {
            let timer = null
            return function () {
                let context = this;
                if (!timer) {
                    timer = setTimeout(() => {
                        fn.apply(this)
                        timer = null
                    }, 200)
                }
            }
        }


    </script>
</body>

</html>

方法三: intersectionObserve()

IntersectionObserver : 浏览器原生提供的构造函数,接收两个参数

IntersectionObserver API 是异步的,不会与目标元素的滚动同步触发

html 复制代码
<!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>Document</title>
    <style>
        img {
            background: url('./img/loading.gif') no-repeat center;
            width: 250px;
            height: 250px;
            display: block;
        }
    </style>
</head>

<body>
    <img src="./img/pixel.gif" data-url="./img/1.jpeg">
    <img src="./img/pixel.gif" data-url="./img/2.jfif">
    <img src="./img/pixel.gif" data-url="./img/3.jfif">
    <img src="./img/pixel.gif" data-url="./img/4.jfif">
    <img src="./img/pixel.gif" data-url="./img/5.jfif">
    <img src="./img/pixel.gif" data-url="./img/6.webp">

    <script>

        let imgs = document.getElementsByTagName('img')
        // 1. 一上来立即执行一次
        let io = new IntersectionObserver(function (entires) {
            //图片进入视口时就执行回调
            entires.forEach(item => {
                // 获取目标元素
                let oImg = item.target
                // console.log(item);
                // 当图片进入视口的时候,就赋值图片的真实地址
                if (item.intersectionRatio > 0 && item.intersectionRatio <= 1) {
                    oImg.setAttribute('src', oImg.getAttribute('data-url'))
                }
            })
        })
        Array.from(imgs).forEach(element => {
            io.observe(element)  //给每一个图片设置监听
        });
    </script>
</body>

</html>
相关推荐
m0_7482550226 分钟前
前端常用算法集合
前端·算法
真的很上进40 分钟前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203981 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2341 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1232 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~3 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语3 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport3 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg3 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全
胡西风_foxww3 小时前
【es6复习笔记】rest参数(7)
前端·笔记·es6·参数·rest