0%

图片懒加载

实现图片懒加载

懒加载是一种网页性能优化方式,提升用户体验,比如懒加载图片,进入页面时,我们只请求可视区域的图片资源

总结:

全部加载会影响用户体验

浪费用户的流量,有些用户不想全部看完,全部加载会耗费大量流量

实现方式:

html实现

最简单的实现方式给img标签加上 loading=”lazy”

1
<img src="./example.jpg" loading="lazy">

js实现原理

  • 通过js监听页面的滚动
  • 使用js实现的原理主要是判断当前图片是否到了可视区域:
  • 拿到所有图片的dom
  • 遍历每个图片判断当前图片是否到达了可视区域范围
  • 如果到了就设置图片的src属性
  • 绑定window的scroll事件,对其进行事件监听

在页面初始化时,img图片的src放在data-src属性上,当匀速处于可视区范围,就把data-src赋值给src属性,完成图片加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Lazyload</title>
<style>
img {
display: block;
margin-bottom: 50px;
height: 200px;
width: 400px;
}
</style>
</head>
<body>
<img src="./img/default.png" data-src="./img/1.jpg" />
<img src="./img/default.png" data-src="./img/2.jpg" />
<img src="./img/default.png" data-src="./img/3.jpg" />
<img src="./img/default.png" data-src="./img/4.jpg" />
<img src="./img/default.png" data-src="./img/5.jpg" />
<img src="./img/default.png" data-src="./img/6.jpg" />
<img src="./img/default.png" data-src="./img/7.jpg" />
<img src="./img/default.png" data-src="./img/8.jpg" />
<img src="./img/default.png" data-src="./img/9.jpg" />
<img src="./img/default.png" data-src="./img/10.jpg" />
</body>
</html>

先获取所有图片的dom,通过document.body.clientHeight获取可视区高度,在使用element.getBoundingClientRect()直接得到元素相对浏览器的top值,遍历每个图片判断图片是否到达了可视区域

1
2
3
4
5
6
7
8
9
10
11
12
13
function lazyLoad(){
let viewHeight=document.body.clientHeight;//获取可视区高度
let imgs=document.querySelectorAll("img[data-src]")
imgs.forEach(item=>{
if(item.data-src=='')return;
let rect=item.getBoundingClientRect();
if(rect.top<viewHeight&&rect.bottom>=0){
item.src=item.data-src
item.removeAttribute('data-src')

}
})
}

这样存在性能问题,因为scroll事件会在很短事件内触发多次,严重影响页面性能,为了提高网页性能,我们需要一个节流函数来控制函数的多次触发,在一段时间内只执行一次回调

1
2
3
4
5
6
7
8
9
10
11
12
13
function throttle(fn,delay){
let timer=null;
return function(fn,...args){
const context=this;
if(!temer){
timer=setTimeout(()=>{
fn.apply(context,args);
timer=null;
})
}
}

}

scroll

1
window.addEventListener("scroll",throttle(lazyload,200))

拓展: IntersectionObserver

通过上面例子的实现,我们要实现懒加载都需要去监听 scroll 事件,尽管我们可以通过函数节流的方式来阻止高频率的执行函数,但是我们还是需要去计算 scrollTop,offsetHeight 等属性,有没有简单的不需要计算这些属性的方式呢,答案就是 IntersectionObserver

IntersectionObserver 是一个比较新的 API,可以自动”观察”元素是否可见,Chrome 51+ 已经支持。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做”交叉观察器”。我们来看一下它的用法

[]: https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const imgs=document.querySelectorAll("img[data-src]");
const config={
rootMargin:'0px',
threshold:0
}
let observer=new IntersectionObserver((entries,self)=>{
entries.forEach((entry)=>{
if(entry.isIntersecting){
let img=entry.target;
let realsrc=img.dataset.src;
if(src){
img.src=realsrc;
img.removeAttribute('data-src')
}
self.unobserve(entry.target);//解除观察
}
})
},config)
imgs.forEach((image)=>{
observer.observe(image)
})