社区精选 | 用原生的 JavaScript Intersection Observer API 实现 Lazy Loading
今天为各位带来的是社区作者 前端小智 的文章,在这篇文章中他为大家介绍了 Intersection Observer API。
前一阵子在做一个项目的时候,因为每组数据都要先通过很庞大的计算,才把计算后的结果 Render 到页面上,但这样就导致如果单页查出来的数据超过大概 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,那只要会上方的几种使用方式就绰绰有馀了!
地址:
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
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 秒
SegmentFault 思否社区小编说
自 2022-07-01 起 SegmentFault 思否公众号改版啦!之后将陆续推出新的栏目和大家见面!(请拭目以待呀~❤)
在「社区精选」栏目中,我们将为广大开发者推荐来自 SegmentFault 思否开发者社区的优质技术文章,这些文章全部出自社区中充满智慧的技术创作者哦!
希望通过这一栏目,大家可以共同学习技术干货,GET 新技能和各种花式技术小 Tips。
欢迎越来越多的开发者加入创作者的行列,我们将持续甄选出社区中优质的内容推介给更多人,让闪闪发光的技术创作者们走到聚光灯下,被更多人认识。
「社区精选」投稿邮箱:pr@segmentfault.com
投稿请附上社区文章地址