本文介绍如何使用原生JavaScript的Intersection Observer API实现高效的图片与数据懒加载。通过监听元素与视口的相交状态,避免一次性加载大量数据导致的性能问题,提升用户体验。文章涵盖API基本用法、具体实现步骤及注意事项,并提供完整代码示例。
引言
在近期开发的一个项目中,每组数据都需要经过复杂的计算处理才能渲染到页面上。如果单页查询的数据量超过大约5条,用户就需要等待一段明显的时间才能看到结果,这严重影响了使用体验。
为了解决这一糟糕的用户体验,我们采用了标题中提到的Lazy Loading(懒加载)技术。简单来说,虽然需要展示的数据总量有10条,但一个页面通常只能呈现2到3条。因此,我们优先计算并显示这2到3条数据,剩余的数据则等待用户向下滚动时再加载显示,从而避免了长时间的等待。
作为前端工程师,在想到这个解决方案后,自然想到去GitHub寻找一个简单便捷的组件来解决这个问题。最终找到的vue-scroll-loader组件使用非常简单,代码量也很少。在处理完相关issue后,我研究了它内部如何实现Lazy Loading,从而引出了本文主要讲解的Intersection Observer API。

Intersection Observer API
那么,Intersection Observer API到底是什么?为什么它可以用来实现Lazy Loading呢?根据MDN的说法:
Intersection Observer API提供了一种异步检测目标元素与祖先元素或viewport(视口)相交情况变化的方法。
简单来说,只要使用Intersection Observer API,就能监听目标元素在画面上出现或离开时,执行你交给它的callback(回调)方法。下面来看看具体的使用方式。
使用方法
首先,我们需要简单的HTML和CSS结构,主要目标是将div放置在向下滚动才会出现的位置:
body {
height: 1000px;
}
.box {
width: 100px;
height: 100px;
background: #000;
position: absolute;
top: 500px;
}<body>
<div class="box"></div>
</body>接着,我们使用Intersection Observer API的observe方法,把要监听的div作为参数传给它,并用callback让它可以在div出现和离开的时候给出消息:
const intersectionObserver = new IntersectionObserver(
() => { console.log('hi'); }
);
intersectionObserver.observe(
document.querySelector('.box')
);执行的结果就会像这样子:

而Intersection Observer API在执行callback的时候,也会给你一个Array,Array是所有正在监听的元素列表。我们可以从这些元素里的isIntersecting属性来判断当前元素是出现在画面中,还是离开了画面:
const intersectionObserver = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
console.log('我進來了!');
} else {
console.log('我又出去了!');
}
}
);
intersectionObserver.observe(
document.querySelector('.box')
);执行结果:

最后,当你不再需要继续监听元素的时候,可以使用unobserve来解除监听。使用时就像监听用的observe一样,给它不需要再监听的元素:
intersectionObserver.unobserve(
document.querySelector('.box')
);以上就是Intersection Observer API的基本用法。当然,还有其他更详细的设置(可以参考MDN的介绍),但如果要完成一个简单的Lazy Loading,只要掌握上述几种使用方式就绰绰有余了。
Lazy Loading
使用Intersection Observer API实现Lazy Loading的方法是在数据列表的最后放置一个loading的小动画。接着,只要去监听这个小动画,当它出现在页面中时,利用Intersection Observer API的callback来载入更多数据。
首先,同样先简单写个要显示数据的<ul>,以及要监听的元素。这里我就不做小动画了,直接用Loading…文字代替:
<body>
<ul class="list"></ul>
<div class="loading">Loading...</div>
</body>要注意,监听的元素必须放在载入数据的最下面哦!不然它不会被监听到“出现在页面上”(这个下方会更详细说明注意事项)。
JavaScript的部分先贴代码,下方再来解释:
const data = Array.from(Array(200)).map(
(_value, index) => `第 ${index + 1} 筆資料`
);
const render = () => {
const list = document.querySelector('.list');
const LOAD_DATA_COUNT = 50;
const startLoadIndex = list.childNodes.length;
const endLoadIndex = startLoadIndex + LOAD_DATA_COUNT;
for (let i = startLoadIndex; i < endLoadIndex; i++) {
if (data[i]) {
const text = document.createTextNode(data[i]);
const li = document.createElement('li');
li.appendChild(text);
list.appendChild(li);
}
}
if (endLoadIndex >= data.length) {
const loading = document.querySelector('.loading');
loading.style.display = 'none';
intersectionObserver.unobserve(loading);
}
};
render();
const intersectionObserver = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
setTimeout(render, 1000);
}
}
);
intersectionObserver.observe(
document.querySelector('.loading')
);- 先用循环产生200笔的假数据
- 写一个
render的方法,把还没载入的数据循环加进去,这里一次加50笔数据 - 在
render内加完数据后,去判断当前加到的index有没有大于数据总数。如果有的话,代表所有数据显示完了,因此隐藏loading,并移除Intersection Observer API对loading的监听 - 毕竟一开始画面上还是要有数据!所以先手动执行第一次
render方法 - 用Intersection Observer API监听
loading,只要一出现在画面上(代表使用者看完目前的数据),就要在执行render。这里为了有真正render的感觉,我用setTimeout来延迟1秒
执行的效果就会像这样子:

但是还有一点要注意的地方,以上方的例子来说,如果Intersection Observer API因为loading出现在页面中执行了render,但是render后的数据量却不足以把loading移到画面外,那loading就会一直停留在画面中,而不是“出现在画面中”。这样一来,Intersection Observer API也就不会触发render来载入更多数据。
最后来看一下支持情况。Intersection Observer API的支持度算不错了,但如果产品有要考虑到IE的客户群就没办法用了。

最后还是觉得从开源项目里面可以学到很多有趣的东西,也推荐大家可以在使用某些组件时候偷看一下背后的源码是怎么处理的。
~完,我是刷碗智,新的一年,我们一起洗刷刷新!!
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://medium.com/starbugs/%...
以上就是原生JS Intersection Observer API实现懒加载的详细内容,更多关于JS Intersection Observer API懒加载的资料请关注本站其它相关文章!