图片懒加载

简介

图片懒加载是指在web应用中,让图片这种耗流量的资源只在网页可视区域显示出来,只有在用户滑动到相应的其他区域时,再加载其他图片。比如淘宝首页,页面内容非常的多,图片可能有成百上千张,但是大部分用户只会浏览到第一屏显示的图片,而页面其他图片就没有必要显示出来了。因为这种亿万级别的网站,省流量就是省钱。

实现步骤

  1. 将所有图片页面上面所有图片的真实地址指定到data-src属性中,src统一写为一张加载中的动画图片地址
  2. 监控页面的滚动行为,在每次滚动的时候遍历图片的dom,计算图片的位置是否在网页的可视区域,如果存在的话,就将图片的src替换为data-src
  3. 由于页面滚动计算是高耗资源的操作,可以在滚动的时候加上throttle

下面具体实现

方法1

准备一下dom结构:

1
2
<img src="https://i.loli.net/2018/12/09/5c0bfcc33d7f8.png" data-src="https://i.loli.net/2018/11/23/5bf75ff39e0a4.jpg" />
....

实现如下脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function queryImage() {
return Array.from(document.querySelectorAll('img'))
}
function scrollFn() {
const images = queryImage()
const windowHeight = window.innerHeight
images.forEach(image => {
const rect = image.getBoundingClientRect()
if (rect.top > 0 && rect.top < windowHeight && image.getAttribute('data-src')) {
image.src = image.getAttribute('data-src')
image.onload = function() {
image.removeAttribute('data-src')
}
image.onerror = function() {
image.src = 'http://iph.href.lu/100x100?text=img%20error&fg=E74C3C'
}
}
})
}
// 这里使用了lodash的throttle,其实可以自己实现,代码也就那么几行
document.addEventListener('scroll', _.throttle(scrollFn, 200))
scrollFn()

查看效果demo

方法2

该方法只是在实现图片是否在页面显示区域的逻辑上用了最新的API: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
27
function queryImage() {
return Array.from(document.querySelectorAll('.img'))
}
const observer = new IntersectionObserver(changes => {
changes.forEach(item => {
const intersectionRect = item.intersectionRect
const img = item.target
if (intersectionRect.height * intersectionRect.width > 0) {
img.addEventListener('load', () => {
observer.unobserve(img)
img.removeAttribute('height')
})
img.addEventListener('error', () => {
img.src = 'http://iph.href.lu/100x100?text=img%20error&fg=E74C3C'
observer.unobserve(img)
})
/* 假装模拟1s */
setTimeout(_ => {
const src = img.getAttribute('data-src')
img.src = src
}, 1000)
}
})
})
queryImage().forEach(img => {
observer.observe(img)
})

查看效果demo

两种方法对比

  • 方法1思路清晰,比较容易理解,兼容性比较好,但是如果是横向滚动的页面就需要另外计算显示逻辑了
  • 方法2为浏览器自带原生API在性能上好,唯一的缺点就是兼容性不行,但是可以通过polyfill来实现
  • 具体怎么选择就看你了
坚持原创技术分享,您的支持将鼓励我继续创作!