IntersectionObserver是什么?
IntersectionObserver是一个新的web API,可以自动检测某个元素是否出现在页面可视区,所以有一个通俗的名字叫 “交叉观察器”,Chrome 51+ 已经支持该特性。更详细的介绍可以看看阮一峰大神的文章:《IntersectionObserver API 使用教程》
为什么要用IntersectionObserver特性?
在此之前,我们监听页面元素是否出现在可视区,或者实现图片懒加载都是通过监听 scoll 事件,而scoll事件密集发生,容易造成性能问题。
话不多说,我们开始撸码!
HTML部分
<div class="img-list">
<ul>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file06.16sucai.com/2018/0423/43a7fbe301d6d3a4c1daadd46bda8996.jpg"></li>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file06.16sucai.com/2018/0423/d4c853a6b08d285c809c0f22af04f4d5.jpg"></li>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file03.16sucai.com/2017/1100/16sucai_P591F3A175.JPG"></li>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file06.16sucai.com/2018/0423/18a5cf4ab618e6736806db42a7a6197b.jpg"></li>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file06.16sucai.com/2018/0423/7dcfc1aede6cd99b583f4149e3ad73ac.jpg"></li>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file06.16sucai.com/2018/0315/fa9f74d6296cd7a1ad9b79e480556c3f.jpg"></li>
<li><img src="https://placehold.it/300&text=Loading..." data-src="https://file06.16sucai.com/2018/0315/8fc2da2c3f645e4afe992ac5c401f4f1.jpg"></li>
</ul>
</div>
CSS部分
<style>
*{padding: 0;margin: 0;list-style: none;}
body {height: auto;width: 300px;margin: auto;}
.img-list li {width: 300px;height: auto;}
.img-list li img {width: 100%;height: auto;}
</style>
JS部分
<script>
window.onload = () => {
var eles = document.querySelectorAll('.img-list li img'); // 获取所有列表元素
// 监听回调
var callback = (entries) => {
entries.forEach(item => {
// 出现到可视区
if (item.intersectionRatio > 0) {
var ele = item.target;
var imgSrc = ele.getAttribute('data-src');
if (imgSrc) {
// 预加载
var img = new Image();
img.addEventListener('load', function() {
ele.src = imgSrc;
}, false);
ele.src = imgSrc;
// 加载过清空路径,避免重复加载
ele.removeAttribute('data-src');
}
}
})
}
var observer = new IntersectionObserver(callback);
// 列表元素加入监听
eles.forEach(item => {
observer.observe(item);
})
}
</script>
实现起来没有什么难度,不过遇到一个问题。当不使用window.onload调用时,由于获取不到元素真实占位,会导致 callback 初次调用时会执行两次(一次是目标元素刚刚进入视口-开始可见,另一次是完全离开视口-开始不可见),这个需要注意。
完整Demo:IntersectionObserver实现懒加载