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,请尝试更新或者使用其他主流浏览器。");
}
});
window.innerHeight
:浏览器可视窗口的高度
document.documentElement.scrollTop
:可视窗口滚动过的距离
元素.offsetTop
:元素相对于其父元素的顶部内边距的距离
元素.offsetHeight
:元素的像素高度
const imgs = document.getElementsByTagName('img');
function throttle(fn, delay) {
let timer = null;
return function() {
let arg = arguments;
let _this = this;
if (!timer) {
timer = setTimeout(() => {
fn.apply(_this, arg);
}, delay)
}
}
}
function lazyLoad(imgs) {
// 浏览器可视窗口的高度;
const windowHeight = window.innerHeight;
// 可视窗口滚动过的距离;
const scrollHeight = document.documentElement.scrollTop;
for (let i = 0; i < imgs.length; i++) {
// !imgs[i].src 是当该图片已加载好之后,无需重复加载
if (
windowHeight + scrollHeight > imgs[i].offsetTop
&& !imgs[i].src
&& imgs[i].offsetTop + imgs[i].offsetHeight > scrollHeight
){
imgs[i].src = imgs[i].dataset.src;
}
}
};
// 进入页面时执行一次加载;
lazyLoad(imgs);
// 监听滚动事件,进行图片懒加载;
window.onscroll = () => throttle(lazyLoad, 300)(imgs);
和方案2大同小异,只是浏览器提供了getBoundingClientRect这个方法,是的计算更加方便了。
const imgs = document.getElementsByTagName('img');
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
rect.top < (window.innerHeight || document.documentElement.clientHeight);
}
function lazyLoad() {
for (let i = 0; i < imgs.length; i++) {
console.log(imgs[i])
if (!imgs[i].src && isInViewport(imgs[i])) {
imgs[i].src = imgs[i].dataset.src;
imgs[i].removeAttribute('data-src');
}
};
}
function throttle(fn, delay) {
let timer = null;
return function() {
let arg = arguments;
let _this = this;
if (!timer) {
timer = setTimeout(() => {
fn.apply(_this, arg);
}, delay)
}
}
}
lazyLoad();
// 监听滚动事件,进行图片懒加载;
window.onscroll = () => throttle(lazyLoad, 300)();
上述方法的测试实例为
<div>
<img data-src="https://p1-q.mafengwo.net/s9/M00/CB/E6/wKgBs1hSPKiAXvE9ABIa6R4tA3U20.jpeg?imageView2%2F2%2Fw%2F1360%2Fq%2F90" />
<img data-src="https://lu17996.com/ueditor/php/upload/image/20220316/1647419221190368.jpeg" />
<img data-src="https://5b0988e595225.cdn.sohucs.com/images/20190131/80e42b7874f746cb8b8d08b9f82de959.jpeg" />
<img data-src="https://p8.itc.cn/q_70/images03/20230721/54943164094b4f27b98189aceb264a00.jpeg" />
<img data-src="https://p26-sign.bdxiguaimg.com/tos-cn-p-0015/o0JQgDsH9OfIkAJbjH4kUZeOv8ynAB8mCmiAU3~tplv-pk90l89vgd-crop-center:1280:720.jpeg?x-expires=1705285977&x-signature=LrTgp%2Fkyk0j3i4TNMFzEPexO5BI%3D" />
<img data-src="https://p5.itc.cn/images01/20210401/2df3cac26bec4838998a9a122df2cd0b.jpeg" />
div>
<style>
img {
height: 100vh;
display: block;
margin-bottom: 50px;
}
style>