[前端学习]学习笔记:图片懒加载技术

一、内容概述

  图片懒加载技术,通俗点来说,就是只有当用户滚动到页面的某部分,需要显示的图片才会被加载。这样可以减少初次加载页面时的请求量,加快页面加载速度,并减少带宽使用,从而优化用户体验。

二、代码详解

  学习笔记已以注释的形式随在各个重要的代码后。

  首先是HTML部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图片懒加载学习笔记</title>
</head>
<body>

<!-- 假设的图片列表,使用data-src代替src -->
<!-- data-src的值会在懒加载函数中赋值给src,从而完成图片加载 -->
<!-- 这里把需要懒加载的图片的类统一设置成lazyload,以便于展开下面的DM操作 -->
<img class="lazyload" data-src="image1.jpg" alt="image1">
<img class="lazyload" data-src="image2.jpg" alt="image2">
<img class="lazyload" data-src="image3.jpg" alt="image3">

<!-- 脚本文件 -->
<script type="text/javascript">

  // 这里将呈现我们的懒加载代码

</script>

</body>
</html>

  然后是JS部分。JS中的代码填充到上面的script中

// 这段代码保证了整个script只有在DOM加载完成后才会执行
	document.addEventListener("DOMContentLoaded", function() {
		// 设置的参数"DOMContentLoaded",是一个事件
		// 该事件是在HTML文档被完全加载和解析后立即触发
		// 不需要等待样式表、图片这些加载完成
		
	    let lazyloadImages = document.querySelectorAll("img.lazyload");
		// 设置变量来搜寻所有img标签中的lazyload类,即查询所有的需要懒加载的图片
		//这些图片初始时不会加载其src指定的内容,而是等待特定条件触发加载
		
	    let lazyloadThrottleTimeout;
		// 该变量用来实现节流功能,具体原因和实现原理我写在用到他的部分
	
	    // 检查图片是否在可视区域的函数
	    function lazyload() {
			// 函数思路:该函数检查每个需要懒加载的图片是否进入用户可视区域。
			// 若是,则将data-src的值赋值给src,进行图片加载
			// 并移除lazyload类标记图片已经加载了
	        if(lazyloadThrottleTimeout) {
				// 节流
	            clearTimeout(lazyloadThrottleTimeout);
	        }    
	
	        lazyloadThrottleTimeout = setTimeout(function() {
				// 设置节流的原因:
				// 如果不使用节流函数,那么滚动、窗口大小变化或设备方向变化时,lazyload函数会在每次事件触发时立即执行。
				// 考虑到这些事件可能会以非常高的频率连续触发(尤其是滚动事件),
				// lazyload函数的频繁执行可能会导致服务器资源浪费、增加性能负担等问题
				// 节流实现原理:
				// 节流函数通过设置一个定时器(setTimeout)来延迟函数的执行,并在延迟期间内忽略接下来触发的函数调用请求。
				// 在这段代码中,lazyload 函数被设置为在滚动、窗口大小变化或设备方向变化时调用,但实际上,它通过setTimeout延迟20毫秒执行。
				// 如果在这20毫秒内事件再次被触发(例如用户持续滚动页面),则通过clearTimeout取消之前设置的定时器
				// 并重新设置一个新的定时器。这样做的结果是lazyload函数在短时间内不会被连续调用,而是每20毫秒最多调用一次。
	            let scrollTop = window.pageYOffset;
	            lazyloadImages.forEach(function(img) {
	                if(img.offsetTop < (window.innerHeight + scrollTop)) {
						// 用户的某些操作使得图片进入用户视线范围
	                    img.src = img.dataset.src;
	                    img.classList.remove('lazyload');
						// 移除标签
	                }
	            });
	            if(lazyloadImages.length == 0) { 
	                document.removeEventListener("scroll", lazyload);
	                window.removeEventListener("resize", lazyload);
	                window.removeEventListener("orientationChange", lazyload);
	            }
	        }, 20);
	    }
	
	    // 使用Intersection Observer API
	    if ("IntersectionObserver" in window) {
			// 如果浏览器支持IntersectionObserver API
			// 将使用此更现代的方法来观察图片是否进入可视区域。
	        let observer = new IntersectionObserver(function(entries, observer) {
	            entries.forEach(function(entry) {
					// 异步检测目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态
	                if (entry.isIntersecting) {
	                    let img = entry.target;
	                    img.src = img.dataset.src;
	                    img.classList.remove("lazyload");
	                    observer.unobserve(img);
	                }
	            });
	        });
	
	        lazyloadImages.forEach(function(img) {
	            observer.observe(img);
	        });
	    } else {
	        // 备用方案:监听滚动事件
			// 对于不支持IntersectionObserver的浏览器
			// 代码回退到监听scroll、resize和orientationChange事件
			// 并在这些事件发生时执行懒加载函数
			
	        document.addEventListener("scroll", lazyload);
	        window.addEventListener("resize", lazyload);
	        window.addEventListener("orientationChange", lazyload);
			// 确保了无论用户是通过滚动、调整窗口大小还是改变设备方向
			// 只要图片进入可视区域,就会触发加载。
	    }
	});

三、没有注释的简洁代码

document.addEventListener("DOMContentLoaded", function() {
let lazyloadImages = document.querySelectorAll("img.lazyload");
let lazyloadThrottleTimeout;
function lazyload() {
    if(lazyloadThrottleTimeout) {
        clearTimeout(lazyloadThrottleTimeout);
    }    

    lazyloadThrottleTimeout = setTimeout(function() {
        let scrollTop = window.pageYOffset;
        lazyloadImages.forEach(function(img) {
            if(img.offsetTop < (window.innerHeight + scrollTop)) {
                img.src = img.dataset.src;
                img.classList.remove('lazyload');
            }
        });
        if(lazyloadImages.length == 0) { 
            document.removeEventListener("scroll", lazyload);
            window.removeEventListener("resize", lazyload);
            window.removeEventListener("orientationChange", lazyload);
        }
    }, 20);
}
if ("IntersectionObserver" in window) {
    let observer = new IntersectionObserver(function(entries, observer) {
        entries.forEach(function(entry) {
            if (entry.isIntersecting) {
                let img = entry.target;
                img.src = img.dataset.src;
                img.classList.remove("lazyload");
                observer.unobserve(img);
            }
        });
    });

    lazyloadImages.forEach(function(img) {
        observer.observe(img);
    });
} else {
    document.addEventListener("scroll", lazyload);
    window.addEventListener("resize", lazyload);
    window.addEventListener("orientationChange", lazyload);
}
});

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值