实现图片懒加载

前言

图片懒加载在一些图片密集型的网站中运用比较多,通过图片懒加载可以让一些不可视的图片不去加载,避免一次性加载过多的图片导致请求阻塞(浏览器一般对同一域名 下的并发请求的连接数有限制),这样就可以提高网站的加载速度,提高用户体验。

效果预览


如何做

步骤一

首先我们需要让我们html中需要懒加载的img标签的src设置缩略图或者不设置src,然后自定义一个属性,值为真正的图片或者原图的地址(比如下面的data-src), 并且定义一个类名,表示该图片是需要懒加载的(比如下面例子的lazy-image),这有两个作用:

  1. 为以后获取需要懒加载图片的img元素
  2. 可以给这个类名设置背景图片,作为图片未加载前的过度图片,比如显示为loading的图片。
1
2
3
4
5
<img data-src="https://tb1.bdstatic.com/tb/cms/liveshow/ent_slid2.jpg" class="lazy-image"/> 
// css部分
.lazy-image {
background: url('../img/loading.gif') no-repeat center;
}

步骤二

页面加载完后,我们需要获取所有需要懒加载的图片的元素集合,判断是否在可视区域,如果是在可视区域的话,设置元素的src属性值为真正图片的地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
inViewShow() {     
let imageElements = Array.prototype.slice.call(document.querySelectorAll('.lazy-image'))
let len = imageElements.length
for(let i = 0; i < len; i++) {
let imageElement = imageElements[i]
const rect = imageElement.getBoundingClientRect() // 出现在视野的时候加载图片
if(rect.top < document.documentElement.clientHeight) {
imageElement.src = imageElement.dataset.src // 移除掉已经显示的
imageElements.splice(i, 1)
len--
i--
}
}
}

这里判断是否出现在可视区域内,是通过获取元素的getBoundingClientRect属性的top值和页面的clientHeight进行对比,如果top值小于clientHeight,则说 明元素出现在可视区域了。BoundingClientRect是获取某个元素相对于视窗的位置集合,见下图,注意bottom和right和我们平时的bottom和right不一样。

lazyload2

步骤三

用户滚动窗口的时候,遍历所有需要懒加载的元素,通过每个元素的BoundingClientRect属性来判断元素是否出现在可视区域内,判断方法同第二步一样。

1
document.addEventListener('scroll', inViewShow)

这里我们可以优化下,可以通过函数节流优化滚动事件的处理函数。

补充-利用高级特性Intersection Observer来判断元素是否可见。

上面我们利用元素的BoundingClientRect的top属性和body的clientHeight来判断元素是否可见,这种传统方式获取元素是否可见的一个缺点是我们还需要绑定 scroll事件,scroll事件是伴随着大量计算的,会造成资源浪费,虽然我们可以通过节流函数来提高性能,但还是会有性能浪费的问题,而Intersection Observer 可以不用监听scroll事件,做到元素一可见便调用回调,在回调里面我们来判断元素是否可见。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if ("IntersectionObserver" in window) {        
let lazyImageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry, index) => {
// 如果元素可见
if (entry.intersectionRatio > 0) {
let lazyImage = entry.target
lazyImage.src = lazyImage.dataset.src
lazyImage.classList.remove("lazy-image")
lazyImageObserver.unobserve(lazyImage)
// this.lazyImages.splice(index, 1)
}
})
})
this.lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
})
}

仓库代码

lazyload

在线预览

本文结束感谢您的阅读

本文标题:实现图片懒加载

文章作者:陈宇(cosyer)

发布时间:2020年07月01日 - 23:07

最后更新:2020年07月02日 - 00:07

原始链接:http://mydearest.cn/2020/%E5%AE%9E%E7%8E%B0%E5%9B%BE%E7%89%87%E6%87%92%E5%8A%A0%E8%BD%BD.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!