介绍
所谓的图片懒(延迟)加载就是指图片出现在我们的视口(viewport)内才进行加载,这样可以有效的减轻服务器压力和节省流量。
想想,如果一个长列表页面,共有100张图片,但是我们首先看到的只有视口内前几张,那么视口以下的图片我们可能并没有看到,这样如果全都下载,那么就是一种资源的浪费,增加服务器压力,同时也浪费流量。
如何实现
这里教给大家三种方式来实现:
- 传统的 el.offsetTop < clientHeight + scrollTop位置来判断
- Element.getBoundingClientRect():此方法返回元素的大小及其相对于视口的位置
- IntersectionObserver():提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。此种效率是最高的。
方式一实现: offsetTop
原理图:
页面布局结构
<body>
<p>111111111111111111</p>
<p>111111111111111111</p>
<p>111111111111111111</p>
<p>111111111111111111</p>
<p>111111111111111111</p>
<p>111111111111111111</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<p>2222222222222222</p>
<img width="200px" data-src="https://img0.baidu.com/it/u=593652383,3007722262&fm=26&fmt=auto&gp=0.jpg" alt=""> <br />
<img width="200px" data-src="https://img1.baidu.com/it/u=2247241615,3725296843&fm=26&fmt=auto&gp=0.jpg" alt=""> <br />
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<h3>3333333333333333333</h3>
<img id="imgabc" width="200px" data-src="https://img0.baidu.com/it/u=2658555271,1114326008&fm=26&fmt=auto&gp=0.jpg" alt="">
<br />
<h3>44444444444</h3>
<h3>44444444444</h3>
<h3>44444444444</h3>
<h3>44444444444</h3>
<h3>44444444444</h3>
</body>
js:
<script>
let imgs = document.querySelectorAll('img');
function scrollHandle(imgs){
let pageScrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
// 或 window.innerHeight
let clientHeight = document.documentElement.clientHeight;
imgs.forEach(img => {
let offsetTop = img.offsetTop;
let done = img.getAttribute('loaded');
// 提前50像素预加载
if(offsetTop - 50 < pageScrollTop + clientHeight){
!done && (img.src = img.getAttribute('data-src')) && img.setAttribute('loaded', 'done')
}
})
}
window.onscroll = function(event){
scrollHandle(imgs)
};
// 初始化一次 immediate
scrollHandle(imgs)
</script>
打开浏览器体验吧!!
方式二:getBoundingClientRect
Element.getBoundingClientRect():此方法返回元素的大小及其相对于视口的位置
原理:
<script>
let imgs = document.querySelectorAll('img');
let windonHeight = window.innerHeight;
console.log(windonHeight);
window.onscroll = function () {
imgs.forEach(img => {
if (img.getAttribute('isDone')) {
return;
}
let top = img.getBoundingClientRect().top;
if (top > 0 && top < windonHeight) {
console.log('jiazai ');
img.src = img.getAttribute('data-src');
img.setAttribute('isDone', true)
}
})
}
</script>
方式三: IntersectionObserver
IntersectionObserver():提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。此种效率是最高的。
<script>
let imgs = document.querySelectorAll('img');
let observer = new IntersectionObserver((entries)=>{
// 观察所有
entries.forEach( entry => {
if(entry.isIntersecting){
const image = entry.target;
image.src = image.getAttribute('data-src');
console.log('requesting')
// 取消观察
observer.unobserve(image)
}
} )
})
imgs.forEach(img => {
observer.observe(img)
})
</script>
有名的Vue-lazyload模块底层也采用了IntersectionObserver方案来实现。
效果:
注意:此方式IE不兼容