1. 什么是懒加载?
当我们碰到长网页有很多图片时,我们会采用先加载出现在视口内的几张图片,当滚动条滚动到相应图片的位置时才去加载别的图片。这种延迟加载的方式我们就称之为懒加载。
2. 懒加载的优点
- 提升用户体验
假设一个场景:当我们浏览淘宝的时候,页面需要加载很长时间才能显示出来,根据3秒钟定律,此时用户肯定已经失去了耐心。但是使用懒加载就能够大大提升页面的展现速度,从而提升用户体验。
- 减轻服务器压力
想象一下,如果一个人需要在短时间内做很多事情,那这个人肯定压力会很大。服务器也是一样的,我们通过懒加载就减轻了服务器的工作量,让它有时间缓一缓,再来处理后面的事情。
3. 实现原理
前面铺垫了这么多,下面重点来了(敲黑板!!!)。
clientHeight
:浏览器视口的高度;scrollTop
:滚动轴滚动的距离;offsetTop
:图片的头部距离浏览器顶部的高度(注意不是距离视口顶部的高度);
我们实现懒加载的想法是一开始只加载显示在视口内的图片,从上图可以看出,我们可以先只加载前两张图片。那么如何保证图片不加载出来呢?
可以通过将图片的地址保存在
img
元素的自定义属性上面,当需要加载的时候再将该自定义属性赋值给该图片的src
。
那么问题来了,什么时候加载后面的图片呢?
就是在我们滚动滚动轴的时候,当下一张图片的顶部马上要出现在视口的时候去加载下一张图片。
好啦,现在我们已经知道该什么去加载下一张图片了。那么接下来是第二个问题:怎么知道下一张图片马上要出现在视口上了呢?
就是当图片距离浏览器顶部的高度---即
offsetTop
<=
视口高度clientHeight
+ 滚动条的长度scrollTop
。这是重点!!!明白了这个后面就简单了
最后一个问题,如何获取offsetTop
、scrollTop
、clientHeight
这三个数值呢?
offsetTop
:直接通过img.offsetTop
就可以获取;scrollTop
:通过document.documentElement.scrollTop
获取;clientHeight
:通过document.documentElement.clientHeight
获取;
此处主要介绍懒加载,对于上述三个api
不熟悉可自行百度学习。建议先记住他们可以这么获取就行。
4. 代码实现
- 首先定义
html
结构和CSS
样式;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
img {
height: 450px;
display: block;
margin-bottom: 20px;
}
</style>
</head>
<body>
<!--图片地址暂时先保存在data-src这个自定义属性上面-->
<img data-src="./img-loop/img/1.jpg" alt="懒加载1" />
<img data-src="./img-loop/img/2.png" alt="懒加载2" />
<img data-src="./img-loop/img/3.jpg" alt="懒加载3" />
<img data-src="./img-loop/img/4.jpg" alt="懒加载4" />
<img data-src="./img-loop/img/5.jpg" alt="懒加载5" />
</body>
</html>
- 下面编写
js
;
const imgs = document.getElementsByTagName('img');
function lazyLoad(imgs) {
// 视口的高度;
const clientH = document.documentElement.clientHeight;
// 滚动的距离,这里的逻辑判断是为了做兼容性处理;
const clientT = document.documentElement.scrollTop || document.body.scrollTop;
for(let i = 0; i < imgs.length; i++) {
// 逻辑判断,如果视口高度+滚动距离 > 图片到浏览器顶部的距离就去加载;
// !imgs[i].src 是避免重复请求,可以把该条件取消试试:可以看到不加该条件的话往回滚动就会重复请求;
if(clientH + clientT > imgs[i].offsetTop && !imgs[i].src) {
// 使用data-xx的自定义属性可以通过dom元素的dataset.xx取得;
imgs[i].src = imgs[i].dataset.src;
}
}
};
// 一开始能够加载显示在视口中的图片;
lazyLoad(imgs);
// 监听滚动事件,加载后面的图片;
window.onscroll = () => lazyLoad(imgs);
至此,我们就完成了开头gif图的懒加载的效果。
5. 性能优化
其实上面的代码还是有很多性能优化的地方,比如说对于频繁触发的
scroll
事件会给浏览器造成很大的压力。我们可以使用节流函数做一个优化;
- 没有优化前,滚动的时候
lazyLoad
函数频繁触发;
- 使用节流函数进行优化;
// 设置节流函数
function throttle(fn, delay) {
let timer = null;
return () => {
if(timer) {
return;
};
timer = setTimeout(() => {
fn(imgs);
timer = null;
}, delay)
}
}
// 监听滚动事件,加载后面的图片;
window.onscroll = throttle(lazyLoad, 500);
- 优化后的效果;