一. 为什么需要图片懒加载?
- 每一张图片都需要一个http请求获取src,如果首页有大量图片,加载时间会变长,用户体验不好。
二. 懒加载原理?有什么好处?
- 用户其实不关心屏幕看不到的地方,懒加载类似于组件的按需加载,在没用到的时候暂时不请求内容,在需要的时候再去发请求。
- 原理:在用户看不到的时候使用loading图占位,真正的图片内容等到图片处于可视范围再请求。
三. 实现
问题1:如何判断图片处于可视范围?
- 两个主要API:
Element.getBoundingClientRect():返回元素的大小及其相对于视口的位置。
window.innerHeight:浏览器窗口的视口(viewport)高度(以像素为单位);如果有水平滚动条,也包括滚动条高度
- 使用
Element.getBoundingClientRect().top
获取图片距离视窗顶部的距离。 - 使用
window.innerHeight
获取视窗高度。 - 判断图片是否在可视范围,只需要判断
Element.getBoundingClientRect().top <= window.innerHeight
问题2:图片的src暂存的是loading图,如何获取真正的图片内容?
- 自定义
data-src
属性,用于存放真正的地址,当图片到了可视范围就使用真正的src替换loading图。
问题3:如何动态获取视窗变化?
- 监听浏览器的滚动条事件,触发判断是否加载的回调。
问题4:滚动时间触发太频繁,如何优化,减少重复判断?
- 对判断方法进行函数防抖。
问题5:已经加载过的图片怎么区分?(避免重复加载)
- 将已经加载过的图片从图片列表中删除。
完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
.container{
width:400px;
}
img{
width:400px;
height:600px;
}
</style>
</head>
<body>
<div class="container">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
<img src="./loading.gif" data-src="./smile.jpg" class="lazy">
</div>
<script>
class LazyLoad{
constructor(className){
this.imgList = [...document.querySelectorAll(className)];
this.judge();
this.bindEvent();
}
// 防抖函数
debounce(fn,delay){
let timer = null;
return function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(fn,delay);
}
}
// 监听滚动条
bindEvent(){
window.addEventListener('scroll',this.debounce(()=>{
this.imgList.length && this.judge();
},200))
}
// 判断是否在可视范围
judge(){
let imgs = this.imgList;
for(let i = 0;i < imgs.length;i++){
if(imgs[i].getBoundingClientRect().top <= window.innerHeight){
this.load(imgs[i],i);
}
}
}
// 将loading图替换为真实地址,加载图片
load(el,index){
let src = el.getAttribute('data-src');
el.src = src;
this.imgList.splice(index,1);
}
}
const lazy = new LazyLoad('.lazy')
</script>
</body>
</html>
-
只需要给需要懒加载的图片加上lazy样式即可。