懒加载的实现 (两种方式)
- 方法一:scroll + getBoundingClientRect
- 方法二:IntersectionObserver(推荐)
codepen 展示
lazyLoad-scroll-getBoundingClientRect-SAM9029
lazyload-IntersectionObserver-SAM9029
进阶–利用getBoundingClientRect实现图片的无限滚动加载 无限滚动懒加载–getBoundingClientRect
- 关于上诉 API 在拓展中有使用介绍!!
- html+css 代码在文章最后(也可在codepen拿到)
一:scroll
+ getBoundingClientRect
思路:使用scroll事件实时检测 目标图像元素的 是否出现的 浏览器(或拥有滑动块的元素)的可视视图内
- 若是 在浏览器视图内懒加载 利用 window.innerHeight 和 目标图像元素.getBoundingClientReact().top 来作比较
- 若是 在拥有滑动块元素视图内懒加载 利用 el.offsetHeight 和 目标图像元素.getBoundingClientReact().top 来作比较
😱缺点:懒加载后无法取消监听,浪费性能
codepen 展示
源码:
let imgList = document.querySelectorAll('img')
window.onscroll = function() {
console.log('执行懒加载监听')
//imgList 本身是 类数组含有 forEach方法同理实现
//此处使用 map 调用call 只是为了加深 改变执行上下文的方法 使用,不必在意
Array.prototype.map.call(imgList,item =>{
// 目标 对象 距离 xx 的顶部距离 小于 当前浏览器窗口的可视高度
if(item.getBoundingClientRect().top < window.innerHeight){
// 将 存储 在data自定义属性中的src 提出 赋值给 img的src
item.src = item.dataset.src
}
})
}
效果图:(待gif)
- 注意 控制台 只要 懒加载完成后,监听依然在执行
二:IntersectionObserver
(推荐)
思路:使用 IntersectionObserver (此为构造函数)的observe属性方法,判断目标元素是否出现在可视视图中
😱缺点:暂时没想到(该API好像兼容性要考虑),IntersectionObserver的unobserve取消观察完全弥补第一种方法的缺点
codepen 展示
源码:
let imgList = document.querySelectorAll('img')
let imgObserver = new IntersectionObserver(callback)
//我把callback 写在 外面,方便理解,亦可直接写在构造函数参数内
function callback(entries){
console.log('执行懒加载监听')
//被观察的 图片数组对象
entries.forEach(item=>{
// 调用 被观察的目标元素 是否 与可视窗口 出现交叉区域
if(item.isIntersecting){
//获取 被观察的目标元素
const targetImg = item.target
// 将 存储 在data自定义属性中的src 提出 赋值给 img的src
targetImg.src = targetImg.dataset.src
// 在懒加载完成后可执行 停止观察,节约性能资源
imgObserver.unobserve(targetImg)
}
})
}
//每个图片都进行观察
imgList.forEach(item=>{
imgObserver.observe(item)
})
效果图:(待gif)
- 注意 控制台 只要 懒加载完成后,监听就被取消了
拓展
getBoundingClientRect Api
- Element.getBoundingClientRect() 是一个
无参普通函数方法
- 返回一个 DOMRect 对象,其提供了元素的大小及其相对于
视口
的位置。 - 注意
视口
可☞window,也可指具有滚动条的父元素!!!- 返回值是一个对象,其中有(以下为示意例子):
-
{ //元素大小信息 height: 120 width: 100 //元素在窗口的位置信息 top: 571.5 left: 18 bottom: 691.5 right: 118 y: 571.5 x: 18 } ```
示意图
IntersectionObserver Api
- 基本使用讲解:
- 这个 API 叫做"交叉观察器": 观察目标元素与视口是否产生一个交叉区
- 注意:这个 API 是 一个 !!⭐
构造函数
, - 基本语法
let targetImgObserver = new IntersectionObserver(callback, option);
- callback 必填(用于执行交叉观察函数时,申明做什么操作!!)
- option是配置对象(该参数可选)
- 该 构造函数 有两个原型的内置方法 (_target需要被观察的对象节点)
- targetImgObserver.observe(_target) : 监听目标对象
- targetImgObserver.unobserve(_target) : 停止监听目标对象(该方法可用在图片加载为成功后执行)
- 再讲回构造函数的参数
callback
回调函数 (理解起来可能有些难,多看几遍参考文章,多写几遍代码!!)- callback 函数本省也有 参数
_entries
一般写成 箭头函数的形式(见基本使用语法) - 关于 参数
_entries
我们需要知道 这就是构造函数的.observe(_target)
方法调用后拿到的 目标对象(可接受为数组形式,即我们多个对象进行了观察,这种情况下很多见,可结合本次例子理解),并可以调用其的观察信息属性- 常用的
entries.isIntersecting
:返回一个布尔值,下列两种操作均会触发callback:1. 如果目标元素出现在root可视区,返回true。2. 如果从root可视区消失,返回false entries.target
目标元素:即被观察的目标元素
- 常用的
- callback 函数本省也有 参数
- 基本使用语法
let targetImgObserver = new IntersectionObserver(callback = _entries =>{
//code
}, option);
//调用该 观察方法后,回调函数的 _entries 就会拿到 被观察的对象
targetImgObserver.observe(_target)
// 在懒加载完成后可执行 停止观察
// targetImgObserver.unobserve(_target)
- 当然,这个API 的好用之处不止在于用于 懒加载,还用许多场景可用,待探索🤩(可见参考文章)
innerWidht
+ innerHeight
-
innerHeight 返回窗口的文档显示区的高度,如果有垂直滚动条,也包括滚动条高度。
-
innerWidth 返回窗口的文档显示区的宽度,如果有水平滚动条,也包括滚动条高度。
innerWidth 和 innerHeight 是只读属性。
注意:使用 outerWidth 和 outerHeight 属性获取浏览器窗口的宽度与高度。
所有有关 DOM 和 BOM 操作高宽的API
BOM window 有关高宽的属性
- .innerWidht .innerHeight
- .outterWidht .outterHeight
- .screenX .screenY
DOM element 有关高宽的属性
- .clientTop .clientLeft
- .clientWidth .clientHeight
- .offsetTop .offsetLeft
- .offsetWidth .offsetHeight
- .scrollTop .scrollLeft
- .scrollWidth .scrollHeight
本文例子所用的 HTML+CSS 源码
<style>
img{
display: block;
margin: 10px;
width: 100px;
height: 120px;
}
</style>
<!-- 文字 -->
<div>
<div>
<h1>清平乐·六盘山</h1>
<p>
天高云淡,望断南飞雁。
</p>
<p>
不到长城非好汉,屈指行程二万。
</p>
<p>
六盘山上高峰,红旗漫卷西风。
</p>
<p>
今日长缨在手,何时缚住苍龙?
</p>
</div>
<div>
<h1>清平乐·六盘山</h1>
<p>
天高云淡,望断南飞雁。
</p>
<p>
不到长城非好汉,屈指行程二万。
</p>
<p>
六盘山上高峰,红旗漫卷西风。
</p>
<p>
今日长缨在手,何时缚住苍龙?
</p>
</div>
<div>
<h1>清平乐·六盘山</h1>
<p>
天高云淡,望断南飞雁。
</p>
<p>
不到长城非好汉,屈指行程二万。
</p>
<p>
六盘山上高峰,红旗漫卷西风。
</p>
<p>
今日长缨在手,何时缚住苍龙?
</p>
</div>
<div>
<h1>清平乐·六盘山</h1>
<p>
天高云淡,望断南飞雁。
</p>
<p>
不到长城非好汉,屈指行程二万。
</p>
<p>
六盘山上高峰,红旗漫卷西风。
</p>
<p>
今日长缨在手,何时缚住苍龙?
</p>
</div>
</div>
<img data-src='https://i.postimg.cc/QdzdhHzg/i001.jpg' alt="">
<img data-src='https://i.postimg.cc/RF7S7GZG/i002.jpg' alt="">
<img data-src='https://i.postimg.cc/gJFcL1mn/i003.jpg' alt="">
<img data-src='https://i.postimg.cc/ZqyKRJkG/i004.jpg' alt="">
data-src='https://i.postimg.cc/QdzdhHzg/i001.jpg' alt="">
<img data-src='https://i.postimg.cc/RF7S7GZG/i002.jpg' alt="">
<img data-src='https://i.postimg.cc/gJFcL1mn/i003.jpg' alt="">
<img data-src='https://i.postimg.cc/ZqyKRJkG/i004.jpg' alt="">