第一种
图片距离浏览器视口顶部距离 <= 浏览器视口高度 + 页面滚动距离
const imgs = document.getElementsByTagName('img');
function lazyLoad(imgs) {
console.log('触发了');
// 视口的高度;
const clientH = document.documentElement.clientHeight;
// 滚动的距离,这里的逻辑判断是为了做兼容性处理;
const clientT = document.documentElement.scrollTop || document.body.scrollTop;
for(let i = 0; i < imgs.length; i++) {
// 逻辑判断,如果视口高度+滚动距离 > 图片到浏览器顶部的距离就去加载;
// !imgs[i].src 是避免重复请求,可以把该条件取消试试:可以看到不加该条件的话往回滚动就会重复请求;
if(clientH + clientT > imgs[i].offsetTop && !imgs[i].src) {
// 使用data-xx的自定义属性可以通过dom元素的dataset.xx取得;
imgs[i].src = imgs[i].dataset.src;
}
}
};
// 一开始能够加载显示在视口中的图片;
lazyLoad(imgs);
// 设置节流函数
function throttle(fn, delay) {
let timer = null;
return () => {
if(timer) {
return;
};
timer = setTimeout(() => {
fn(imgs);
timer = null;
}, delay)
}
}
// 监听滚动事件,加载后面的图片;
window.onscroll = throttle(lazyLoad, 500);
第二种
Element.getBoundingClientRect()
方法返回元素的大小及其相对于视口的位置。我们可以取得它的top
值,它的top
值就是元素左上角到视口顶部的距离。当Element.getBoundingClientRect().top < 视口高度
时触发加载;
const imgs = document.getElementsByTagName('img');
// 判断元素是否出现在视口内
function isShow(el) {
// 视口高度
const clientH = window.innerHeight;
const bound = el.getBoundingClientRect();
// 判断元素左上角到视口顶部的距离是否小于视口高度
return bound.top < clientH;
};
// 加载图片
function showImg(el) {
if(!el.src) {
el.src = el.dataset.src;
}
}
// 懒加载
function lazyLoad() {
console.log('加载了');
[...imgs].forEach(el => {
if(isShow(el)) {
showImg(el);
}
})
};
lazyLoad();
// 节流函数
function throttle(fn, delay) {
let timer = null;
return () => {
if(timer) {
return;
};
timer = setTimeout(() => {
fn(imgs);
timer = null;
}, delay);
}
};
window.onscroll = throttle(lazyLoad, 500);
第三种
IntersectionObserver
可以异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。也就是说它可以帮助我们去判断一个元素是否出现在视口上。这里只介绍用到的两个属性:
IntersectionObserver.observe()
:使IntersectionObserver开始监听一个目标元素;
isIntersecting
属性:可以判断该元素是否出现在视口内;
实现思路:根据上面介绍的那两个属性,我们可以遍历每个img元素,然后监听每一个元素,最后根据isIntersecting属性去判断元素是否出现在视口内,从而决定是否让它加载。
document.addEventListener("DOMContentLoaded", () => {
if ("IntersectionObserver" in window) {
const imgs = document.getElementsByTagName("img");
const imageObserve = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 通过该属性判断元素是否出现在视口内
if (entry.isIntersecting) {
// entry.target能够取得那个dom元素
const img = entry.target;
img.src = img.dataset.src;
// 解除监视
imageObserve.unobserve(img);
}
});
});
[...imgs].forEach((img) => {
// 开启监视每一个元素
imageObserve.observe(img);
});
} else {
alert("您的浏览器不支持IntersectionObserver!");
}
});
第四种
-
img
标签原生支持loading属性,可取值有:- eager:无论图片是否在可视区,都会直接加载图片
- lazy:推迟图片的加载,当图片滚动到距离可视区域一定阈值(视浏览器的实现而定)的时候,再加载图片
- auto:由浏览器自行决定
参考来源: juejin.cn/post/684790…