图片懒加载的三种方式

方法一:滚动监听 + 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>
相关推荐
醉の虾20 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧28 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm38 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王1 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒1 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
gqkmiss2 小时前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃2 小时前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰2 小时前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter