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实现懒加载