根据请求动态懒加载图片

224 阅读3分钟

思考:假如给你50+张图片,你如何实现懒加载?

我的思路:

  1. 加载loading图片:先在显示9张带着loading图片的div块进行占位
  2. 获取后台数据,根据请求图片数量替换并生成同等数量的带着loading的div块
  3. 利用Image()对象先将图片加载至内存,
  4. 待加载完毕再将图片替换loading.png;

知识预热:

利用图片到 浏览器顶部的距离offsetTop的距离=浏览器可视窗口的距离clientHeight+滚动条距离scrollHeight 的时候开始加载图片。

可视窗口获取api:
  • 原生方法:window.innerHeight 标准浏览器及IE9+
  • document.documentElement.clientHeight 标准浏览器及低版本IE标准模式
  • document.body.clientHeight 低版本混杂模式
  • jQuery方法: $(window).height()
滚动条获取api:
  • 原生方法:window.pageYoffset——IE9+及标准浏览器
  • document.documentElement.scrollTop 兼容ie低版本的标准模式
  • document.body.scrollTop 兼容混杂模式;
  • jQuery方法:$(document).scrollTop();
获取元素本身的位置信息:
  • 原生:ele.offsetTop获取ele距离顶部的距离,距 offsetParent 元素的顶部内边距的距离。
  • jQuery:(o).offset().top元素距离文档顶的距离。

整体实现

  • 在这,我用fetch进行异步请求数据。然后进行div块渲染。
  • 数据请求后直接执行 判断图片是否在可视 界面 ;执行fn();
  • 对window添加监听函数

代码:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片懒加载</title>
    <style>
        html,
        body {
            padding: 0;
            margin: 0;
        }

        .container {
            padding: 10px;
            background-color: darkkhaki;
            width: 100%;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
            justify-content: center;
        }

        .item {
            border: 1px solid darkgray;
            background-color: white;
            margin: 10px;
            padding: 10px;
            width: 400px;
            height: 400px;
            text-align: center;
            line-height: 400px;
        }

        .item img {
            width: 50px;
            height: 50px;
        }

        .item img.over {
            width: 400px;
            height: 400px;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
        <div class="item"><img src="./img/loading.gif"></div>
    </div>
</body>
<script>

    let divItem = document.querySelector('.container'),
        str = '';
	//fetch进行异步请求
    fetch('./data.json').then(res => {
        return res.json();
    }).then(res => {
        let url = res;
        for (let i = 0; i < url.length; i++) {
            str += `<div class="item"><img src="./img/loading.gif" data-src=${url[i]}></div>`;
        }
		//本来想法是向末尾添加元素
        // divItem.insertAdjacentHTML('beforeend', str);
        divItem.innerHTML = str;

        let imgs = document.querySelectorAll('img');
		// 获取元素距离顶部距离
        function getTop(o) {
            let T = o.offsetTop;
            return T;
        }
        //判断图片是否应该渲染
        function fn() {
            //可视高度
            let clientHeight = window.innerHeight || document.documentElement.clientHeight;
            // 滚动条距离
            let scrollHeight = pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            for (let i = 0; i < imgs.length; i++) {
                if (clientHeight + scrollHeight > getTop(imgs[i])) {
                    // 设置延时,形成异步加载效果
                    setTimeout(() => {
                    // 创建一个临时图片,这个图片在内存中不会到页面上去。实现隐形加载;在内存中加载完毕再渲染
                    let temp = new Image();
                    temp.src = imgs[i].getAttribute('data-src');
                    temp.onload = function () {
                        //在内存中加载完毕,替换真图片
                        imgs[i].className = 'over';
                        imgs[i].src = imgs[i].getAttribute('data-src');
                    }
                    }, 1500)
                }
            }
            // 全部加载完毕后,去掉监听事件
            if (document.querySelectorAll('.over').length == imgs.length) {
                window.removeEventListener('scroll', fn, false);
            }
        }
		////请求回来后,直接执行,进行可视界面的图片加载。
        fn();
        window.addEventListener('scroll', fn, false);
    });



</script>

</html>