传统实现方式
传统的图片懒加载实现主要是能通过监听容器的onscroll事件,在事件回调中通过getBoundingClientRect方法来获取元素距离视窗左上角的坐标。然后根据屏幕宽高来判断元素与视窗是否有交集。
但是这种方法有一个很大的缺点:onscroll事件是一个频繁执行的事件,其中伴随着大量的计算,由于js是线程的,所以它会影响页面的渲染性能。
IntersectionObserver实现
IntersectionObjser提供了一种异步观察目标元素与其祖先元素或视窗交叉状态的方法。
实现步骤
html,以vue为例
<div class="container">
<!-- 当此元素出现在视图中时加载图片 -->
<div class="skeleton" ref="lazyImage" v-if="!showImage">
这是骨架屏
</div>
<!-- 这是真实的图片 -->
<img src="url" v-else />
</div>
js
new Vue({
data() {
return {
showImage: false,
url: '图片地址',
intersection: null,
}
},
// 渲染完成后,才能获取到lazyImage
mounted() {
this.intersection = new IntersectionObserver(entries => {
// 因为我们只监听一个元素,所以这里取第0个
const current = entries[0]
// intersectionRatio > 0 时,表示当前元素与视图有交叉
if (current.intersectionRatio > 0) {
// 关闭监听
this.intersection?.disconnect()
// 创建一个Image对象
const image = new Image()
image.src = this.url
// 当图片加载成功后,显示图片,否则还是是显示骨架屏
image.onload = () => {
this.showImage = true;
}
}
})
// 开始监听dom元素
this.intersection.observe(this.$refs.lazyImage)
}
})