故问题拆分成两个:
- 如何判断图片出现在了当前视口 (即如何判断我们能够看到图片)
- 如何控制图片的加载
如何判断图片出现在了当前视口
clientTop
,offsetTop
,clientHeight
以及scrollTop
各种关于图片的高度作比对
这些高度都代表了什么意思?
HTML精确定位:scrollLeft
,scrollWidth
,clientWidth
,offsetWidth
-
scrollHeight
: 获取对象的滚动高度。 -
scrollLeft
:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 -
scrollTop
:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离 -
scrollWidth
:获取对象的滚动宽度 -
offsetHeight
:获取对象相对于版面或由父坐标offsetParent
属性指定的父坐标的高度 -
offsetLeft
:获取对象相对于版面或由offsetParent
属性指定的父坐标的计算左侧位置 -
offsetTop
:获取对象相对于版面或由offsetTop
属性指定的父坐标的计算顶端位置 -
event.clientX
相对文档的水平座标 -
event.clientY
相对文档的垂直座标 -
event.offsetX
相对容器的水平坐标 -
event.offsetY
相对容器的垂直坐标 -
document.documentElement.scrollTop
垂直方向滚动的值 -
event.clientX+document.documentElement.scrollTop
相对文档的水平座标+垂直方向滚动的量
这里是javascript中建造迁移转变代码的常用属性
- 网页可见区域宽:
document.body.clientWidth
; - 网页可见区域高:
document.body.clientHeight
; - 网页可见区域宽:
document.body.offsetWidth
(包含边线的宽); - 网页可见区域高:
document.body.offsetHeight
(包含边线的宽); - 网页正文全文宽:
document.body.scrollWidth
; - 网页正文全文高:
document.body.scrollHeight
; - 网页被卷去的高:
document.body.scrollTop
; - 网页被卷去的左:
document.body.scrollLeft
; - 网页正文项目组上:
window.screenTop
; - 网页正文项目组左:
window.screenLeft
; - 屏幕辨别率的高:
window.screen.height
; - 屏幕辨别率的宽:
window.screen.width
; - 屏幕可用工作区高度:
window.screen.availHeight
;
仅仅知道它静态的高度还不够,我们还需要知道动态的
如何动态?监听window.scroll
事件
如何控制图片的加载
<img data-src="JimiLee.jpg">
首先设置一个临时属性 data-src
,控制加载时使用 src
代替 data-src
改进下,如何判断图片出现在了当前视口
引入一个新的 API, Element.getBoundingClientRect()
方法返回元素的大小及其相对于视口的位置。
https://mdn.mozillademos.org/files/15087/rect.png
那如何判断图片出现在了当前视口呢,根据示例图示意,代码如下,这个就比较好理解了,就可以很容易地背会
// clientHeight 代表当前视口的高度
img.getBoundingClientRect().top < document.documentElement.clientHeight
监听 window.scroll
事件也优化一下
加个节流器,提高性能。工作中一般使用 lodash.throttle
就可以了
_.throttle(func, [wait=0], [options={}])
如何判断图片出现在了当前视口
方案二使用的方法是: window.scroll
监听 Element.getBoundingClientRect()
并使用 _.throttle
节流
一系列组合动作太复杂了,于是浏览器出了一个三合一事件: IntersectionObserver
API,一个能够监听元素是否到了当前视口的事件,一步到位!
事件回调的参数是IntersectionObserverEntry
的集合,代表关于是否在可见视口的一系列值
其中,entry.isIntersecting
代表目标元素可见
const observer = new IntersectionObserver((changes) => {
// changes: 目标元素集合
changes.forEach((change) => {
// intersectionRatio
if (change.isIntersecting) {
const img = change.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
})
observer.observe(img)
当然,IntersectionObserver
除了给图片做懒加载外,还可以对单页应用资源做预加载。
总结一下
-
window.scroll
监听各种top
与height
并使用_.throttle
节流,但是不好理解各种top
与hegith
-
window.scroll
监听getBoundingClientRect
并使用_.throttle
节流,没有一个统一事件,相对复杂 -
IntersectionObserver
,浏览器推出了一个事件,方便简单 -
img.loading=lazy
,浏览器直接给你解决,开发者直接标注属性