故問題拆分成兩個:
- 如何判斷圖片出現在了當前視口 (即如何判斷我們能夠看到圖片)
- 如何控制圖片的加載
如何判斷圖片出現在了當前視口
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
,瀏覽器直接給你解決,開發者直接標注屬性