一、原理
只加载可视区域内的图片,而那些还未滑动到可视区域的图片先不加载,直到用户滚动到这些资源即将可见的时候才进行加载。
若一个页面有大量的图片资源,网页首次打开时,若同时加载完这些资源,需要消耗大量的时间,利用图片懒加载,先加载部分图片,既不会影响用户体验,又能大幅提升首屏加载速度。
二、实现
1.那么如何控制图片被加载和不被加载呢?
加载:当网页被打开时,浏览器会自动解析img标签,查看src属性,得到图片url,发请求获取图片资源。
不加载:更改src属性名,变为data-src,这样浏览器就不会自动加载图片资源了。
注:data-* 属性是自定义数据属性,不会影响布局和表现,可以通过DOM元素身上的dataset属性获取,是HTML5引入的新功能。
2.如何判断图片是否在可视区域内呢?
(1)视口方法
利用视口高度window.innerHeight 和 元素距离视口顶部的高getBoundingClientRect().top
若getBoundingClientRect().top < window.innerHeight,则说明元素在可视区域内
(2)页面方法
利用元素距离页面顶部的高度offsetTop 和 页面滚动的高度document.documentElement.scrollTop 和 页面视口高度document.documentElement.clientHeight
三、代码实现
1.监听页面滚动事件
<script>
let images = document.querySelectorAll('img');
//监听滚动事件
window.addEventListener('scroll',()=>{
//滚动高度
let scrollTop = document.documentElement.scrollTop;
//视口高度
let clientHeight = document.documentElement.clientHeight;
images.forEach(image=>{
//进入视口
if(image.offsetTop <= scrollTop + clientHeight){
image.src = image.dataset.src;}
})
})
</script>
痛点:监听事件触发次数太多了!简单滚动就会达到上百次触发
2.优化——Intersection Observer API交叉观察器
这是一种现代的、性能更优的方法,它允许开发者定义一个回调函数,当目标元素与视口的交叉状态变化时自动触发。使用这个API可以更精确地控制懒加载行为,减少滚动事件的直接使用,从而避免潜在的性能问题。
<script>
let images = document.querySelectorAll('img');
//元素引入视口和离开视口都会触发一次
const callback = (entries)=>{
console.log('观察者');
entries.forEach(entry=>{
//与视口相交
if(entry.isIntersecting){
entry.target.src = entry.target.dataset.src;
//图片加载过之后取消监听
observer.unobserve(entry.target);
}
})
}
//构造observer观察器
const observer = new IntersectionObserver(callback);
//观察每一个图片
images.forEach(image=>{
observer.observe(image);
})
</script>