实现图片懒加载
实现原理
- 图片懒加载的原理是通过动态修改img标签的src属性来控制图片的显示与消失。在滚动过程中,如果图片进入了浏览器可视区域,则赋予img标签的src属性正确的图片路径。
- 同时,为img标签上添加一个伪路径属性data-src,里面存放这正确的图片路径,未在浏览器可视区域的img标签的src属性的值是一张loading加载图片,当图片进入到浏览器可视区域,才会将data-src的值赋予给src。
图片懒加载的优势
对于电商等图片很多,页面很长的业务场景适用
减少无效资源的加载:比如我们的页面有100张图片,但是用户往下滑动看的时候只看了十张图片。如果我们把这100张图片全部都加载完成,页面上会有很多的浪费。所以就可以使用懒加载,图片进入可视区域之后再去加载。
并发加载的资源过多会阻塞js的加载,影响网站的正常使用。因为浏览器会限制在一个域名下并发请求的数量。如果前边图片加载数量过多,要发送http请求,就会影响到后边js的并发加载,影响到页面中js逻辑的使用(JS文件一般放在页面底部)。使用图片懒加载可以避免这个问题。
实现思路
- 首先要考虑到一进入浏览器中,可视区域的图片要正常显示。
- 当开始滚动时,每当图片进入到可视区域时,图片从loading图片转换为正常图片,即当滚动区域高度与可视区域的图片高度之和大于未显示图片距离浏览器顶部的距离时,图片展示。
- 向下滚动时,当有图片离开可视区域时,将img标签的src属性置换为loading图片的路径,即当滚动区域高度大于(第i+1张图片的高度和时),将第i张图片的src转变成loading。
PS:如果此时你能理解这一段思路可以暂时不往下看,自己尝试一下如何通过代码去实现
实现前的知识点补充
height、clientHeight、offsetHeight、scrollHeight、innerHeight、outerHeight的区别
height:css属性,可读可写,定义元素内容区的高度,在内容区外面可以增加内边距、边框和外边距。
当 box-sizing: content-box 时,高度应用到元素的内容框。
当 box-sizing:border-box时,高度包含了内容框、内边距和边框。clientHeight:只读属性是没有的CSS或内联布局框元素为零,包含元素的content+padding
offsetHeight:只读属性是元素包括垂直边距和边框的高度,为整数,包含元素的content+padding+border。(不包含外边距)
scrollHeight:只读属性是测量一个元素的含量的高低,包括内容不可见的屏幕上由于溢出。
innerHeight与outerHeight的区别,前者计算元素的高度+padding,后者在前者的基础上加上border和margin。
为什么要用document.documentElement.scrollTop 和 document.body.scrollTop一起来定义滚动条滚动的高度?二者有什么区别?
我们分别输出一下document.documentElement和document.body
body是DOM对象里的body子节点,即 标签;
documentElement 是整个节点树的根节点root,即 标签;
当页面具有 DTD(文档类型定义(Document Type Definition)是一套关于标记符的语法规则),或者说指定了 DOCTYPE 时,使用 document.documentElement才能获取。
页面不具有 DTD,或者说没有指定了 DOCTYPE,时,使用 document.body才能获取。
所以为了兼容处理我们一般通过“||”将两者并用。
实现代码
<!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>
<link rel="stylesheet" href="./reset.css">
</head>
<style>
* {
margin: 0;
padding: 0;
}
#imgList {
width: 300px;
float: left;
padding-left: 650px;
}
#imgList img {
display: block;
width: 300px;
height: 350px;
padding-bottom: 10px;
}
</style>
<body>
<div id="imgList">
<img src="./img/loading.png" data-src="./img/1.3.webp.jpg" alt="photo">
<img src="./img/loading.png" data-src="./img/2.1.webp.jpg" alt="photo">
<img src="./img/loading.png" data-src="./img/2.2.webp.jpg" alt="photo">
<img src="./img/loading.png" data-src="./img/2.3.webp.jpg" alt="photo">
<img src="./img/loading.png" data-src="./img/3.1.webp.jpg" alt="photo">
<img src="./img/loading.png" data-src="./img/3.2.webp.jpg" alt="photo">
<img src="./img/loading.png" data-src="./img/3.3.webp.jpg" alt="photo">
</div>
<script>
window.onload = function () {
// 获取图片列表,即img标签列表
var imgs = document.querySelectorAll('img');
var imgList = document.getElementById('imgList')
// 可视区域高度
var h = window.innerHeight;
// 获取e到浏览器顶部的距离
function getTop(e) {
return e.offsetTop;
}
//懒加载函数
function lazyLoad(imgs) {
var imgHeight = 0;//计算可视区域图片高度
//1.首先可视区域中的图片正常展示
for (let i = 0; i < imgs.length; i++) {
imgs[i].src = imgs[i].getAttribute('data-src');
imgHeight += imgs[i].clientHeight;
if (imgHeight > h) {
break;
}
}
//2.当开始滚动时,当滚动区域高度加上可视区域图片高度大于未显示图片到浏览器顶部的距离时,将src赋予未显示图片
//滚动区域高度
var s = document.documentElement.scrollTop || document.body.scrollTop;
for (let i = 0; i < imgs.length; i++) {
if ((s + imgHeight) > getTop(imgs[i])) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
//3.当滚动区域高度大于(第i+1张图片的高度和时),将第i张图片的src转变成loading
//获取一张图片的高度
var h1 = imgs[1].clientHeight;
for (let i = 0; i < imgs.length; i++) {
if (s > h1 * (i + 1)) {
imgs[i].src = "./img/loading.png";
}
}
}
lazyLoad(imgs);
//滚动函数,d当页面滚动时执行的函数
window.onscroll = function () {
//调用懒加载函数
setTimeout(function () {
lazyLoad(imgs);
}, 1000)
}
}
</script>
</body>
</html>
实现效果
当我打开页面时,页面呈现效果如下:处于浏览器可视窗口的两张图src属性指向正常路径,其他未显示图片路径全部都是loading图片的路径。
往下滑动时,第一张图片离开浏览器可视窗口,路径转换为loading图片的路径,位于可视页面的图片路径转换为正常图片路径,效果如图:
优化思考
最后图片懒加载效果就呈现了,但在最后效果呈现时还存在一点不足的地方:当滚轮下滑到底部时,再次上滑到顶部,此时的图片全部正常展示,所有图片的src路径全部指向正常路径,即在上滑过程中,懒加载效果还未实现?我们可以通过什么方法来解决呢?