基于IntersectionObserver的图片懒加载实现

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>图片懒加载</title>
<link href="./css/style.css" rel="stylesheet"/>
</head>
<body>
<div id="view">
<img data-src="http://img.pconline.com.cn/images/upload/upc/tx/wallpaper/1301/05/c0/17135331_1357355776882.jpg" class="lazy-image"/>
<img data-src="http://f.hiphotos.baidu.com/zhidao/pic/item/eac4b74543a982267a3d54978a82b9014b90eb86.jpg" class="lazy-image"/>
<img data-src="http://pic1.win4000.com/wallpaper/2/58b61f7dc6c1d.jpg" class="lazy-image"/>
<img data-src="http://file03.16sucai.com/2017/1100/16sucai_p20161106032_0c2.JPG" class="lazy-image"/>
<img data-src="http://imgsrc.baidu.com/image/c0%3Dpixel_huitu%2C0%2C0%2C294%2C40/sign=5a7938d38acb39dbd5cd6f16b96e6c48/aec379310a55b3196c79de4c48a98226cffc1702.jpg" class="lazy-image"/>
<img data-src="http://c.hiphotos.baidu.com/zhidao/pic/item/8d5494eef01f3a2987a8062f9f25bc315d607ceb.jpg" class="lazy-image"/>
</div>
</body>
<link href="./css/style.css" rel="stylesheet"/>
<script src="js/lazy-image.js"></script>
<script>
console.log(document.documentElement.clientHeight)
new LazyImage('.lazy-image')
</script>
</html>
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class LazyImage {
constructor(selector) {
// 懒记载图片列表,将伪数组转为数组,以便可以使用数组的api
this.lazyImages = Array.prototype.slice.call(document.querySelectorAll(selector))
this.init()
}

inViewShow() {
// 不支持IntersectionObserver api的情况下判断图片是否出现在可视区域内
let len = this.lazyImages.length
for(let i = 0; i < len; i++) {
let lazyImage = this.lazyImages[i]
const rect = lazyImage.getBoundingClientRect()
// 出现在视野的时候加载图片
if(rect.top < document.documentElement.clientHeight) {
lazyImage.src = lazyImage.dataset.src
// 移除掉已经显示的
this.lazyImages.splice(i, 1)
len--
i--
if(this.lazyImages.length === 0) {
// 如果全部都加载完 则去掉滚动事件监听
document.removeEventListener('scroll', this._throttleFn)
}
}
}
}

throttle(fn, delay = 15, mustRun = 30) {
let t_start = null
let timer = null
let context = this
return function() {
let t_current = +(new Date())
let args = Array.prototype.slice.call(arguments)
clearTimeout(timer)
if(!t_start) {
t_start = t_current
}
if(t_current - t_start > mustRun) {
fn.apply(context, args)
t_start = t_current
} else {
timer = setTimeout(() => {
fn.apply(context, args)
}, delay)
}
}
}

init() {
// 通过IntersectionObserver api判断图片是否出现在可视区域内,不需要监听Scroll来判断
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry, index) => {
// 如果元素可见
if (entry.isIntersecting) {
let lazyImage = entry.target
lazyImage.src = lazyImage.dataset.src
lazyImageObserver.unobserve(lazyImage)
// this.lazyImages.splice(index, 1)
}
})
})
this.lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
})
} else {
this.inViewShow()
this._throttleFn = this.throttle(this.inViewShow)
document.addEventListener('scroll', this._throttleFn)
}

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
html,body {
height: 100%;
width: 100%;
margin: 0;
}

#view {
color: red;
width: 200px;
height: 300px
}

.lazy-image {
background: url('../img/loading.gif') no-repeat center;
}

img{
margin-top: 100px;
background-size: cover;
background-position: center;
width: 490px;
height: 242px;
}