前端圖片懶加載的原理與3種實現(xiàn)方式舉例
一. 圖片懶加載的目的
大型網(wǎng)站如常用的淘寶,京東等頁面,需要展示大量的商品圖片信息,如果打開網(wǎng)頁時讓所有圖片一次性加載完成,需要處理很多次網(wǎng)絡(luò)請求,等待加載時間比較長,用戶體驗感很差。
有一種常用的解決方式是:隨著滾動動態(tài)加載,即圖片的惰性加載。視圖之外的圖片默認(rèn)不加載,隨著頁面的滾動,圖片進入了顯示的范圍,則觸發(fā)圖片的加載顯示。
優(yōu)點:頁面加載速度快,用戶體驗感更好且節(jié)省流量
二. 圖片懶加載的原理方法
1.初始化時,圖片標(biāo)簽的src不能是真實的圖片地址,也不可以是空地址或者壞地址(會出現(xiàn)圖片加載失敗的圖標(biāo))。
2.初始化的時候,可以設(shè)置圖片的src是某一個小型圖片。例如一張1px*1px的透明圖片。由于所有圖片都使用這一張圖片,只會發(fā)送一次請求,不會增加性能負(fù)擔(dān)。將圖片的真實路徑綁定給一個自定義屬性,例如data-url。注意:頁面的img元素,如果沒有src屬性,瀏覽器就不會發(fā)出請求去下載圖片
<img data-url="xxx" src="1px.gif" width="100" height="100"/>
3.定義滾動事件,判斷元素進入視口,則將src替換為真正的url地址。利用js提取data-url的真實圖片地址賦值給src屬性
三. 圖片懶加載的實現(xiàn)方法
圖片懶加載的關(guān)鍵在于獲取元素的位置,并判斷其是否出現(xiàn)在視口。故有以下三種方式
- 滾動監(jiān)聽+scrollTop+offsetTop+innerHeight
- 滾動監(jiān)聽+getBoundingClientRect()
- intersectionObserve()
3.1 滾動監(jiān)聽+scrollTop+offsetTop+innerHeight
- scrollTop:指網(wǎng)頁元素被滾動條卷去的部分。
- offsetTop:元素相對父元素的位置
- innerHeight:當(dāng)前瀏覽器窗口的大小。需要注意兼容性問題。
- IE8及更早版本以前沒有提供取得瀏覽器窗口大小的屬性,不過提供了API:document.documentElement.clientHeight/clientWidth:返回元素內(nèi)容及其內(nèi)邊距所占據(jù)的空間大小。
- IE6中,上述屬性必須在標(biāo)準(zhǔn)模式才有效,如果是混雜模式,需要通過document.body.clientWidth 和 document.body. clientHeight 取得相同信息。
var pageWidth = window.innerWidth var pageHeight = window.innerHeight; if (typeof pageWidth != "number"){ //pageWidth的值不是數(shù)值,說明沒有innerwidth屬性 if (document.compatMode == "CSS1Compat"){ //標(biāo)準(zhǔn)模式 pageWidth = document.documentElement.clientWidth; pageHeight = document.documentElement.clientHeight; } else { //混雜模式 pageWidth = document.body.clientWidth; pageHeight = document.body.clientHeight; } }
- 三個屬性之間的關(guān)系如圖所示,故當(dāng)scrollTop+innerHeight > offsetTop,即圖片在視口內(nèi),否則圖片在可視區(qū)域外。
代碼實現(xiàn)
滾動監(jiān)聽完成圖片懶加載的簡易版本
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } img { margin-top:400px; width: 250px; display: block; } </style> </head> <body> <img src="img/1pxImg.png" data-url="img/1.jpg"> <img src="img/1pxImg.png" data-url="img/2.jpg"> <img src="img/1pxImg.png" data-url="img/3.jpg"> <img src="img/1pxImg.png" data-url="img/4.jpg"> <img src="img/1pxImg.png" data-url="img/5.jpg"> <script> var imgs = document.getElementsByTagName('img') scrollFn() // 監(jiān)聽滾動事件 window.onscroll = scrollFn function scrollFn() { var clietH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop; console.log(clietH, scrollTop); Array.from(imgs).forEach((item) =>{ let eleTop = item.offsetTop // console.log(eleTop) let count = scrollTop + clietH - eleTop console.log(count) // 可設(shè)置為>100 查看懶加載效果 if (count > 0) { //從data-url中取出真實的圖片地址賦值給scr item.setAttribute('src', item.getAttribute('data-url')) } }) } </script> </body> </html>
3.2 滾動監(jiān)聽+getBoundingClientRect() getBoundingClientRect()
Element.getBoundingClientRect()
方法返回元素的大小及其相對于視口的位置。返回一個對象,對象屬性包括top,right
rectObject = object.getBoundingClientRect();
API返回一個對象,即rectObject為一個對象,其包含以下屬性
- rectObject.top:元素上邊到視窗上邊的距離;
- rectObject.right:元素右邊到視窗左邊的距離;
- rectObject.bottom:元素下邊到視窗上邊的距離;
- rectObject.left:元素左邊到視窗左邊的距離;
- rectObject.width:元素自身的寬度
- rectObject.height:元素自身的高度
故當(dāng)rectObject.top的值處于0-視口高度,則元素處于可視區(qū)。即
getBoundingClientRect(ele).top >= 0 && getBoundingClientRect(ele).top <= offsetHeight
代碼實現(xiàn)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } img { margin-top:400px; width: 250px; display: block; } </style> </head> <body> <img src="img/1pxImg.png" data-url="img/1.jpg"> <img src="img/1pxImg.png" data-url="img/2.jpg"> <img src="img/1pxImg.png" data-url="img/3.jpg"> <img src="img/1pxImg.png" data-url="img/4.jpg"> <img src="img/1pxImg.png" data-url="img/5.jpg"> <script> var imgs = document.getElementsByTagName('img') scrollFn() // 監(jiān)聽滾動事件 window.onscroll = scrollFn function scrollFn() { var clietH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; Array.from(imgs).forEach((item) =>{ let ele = item.getBoundingClientRect() console.log(clietH,ele.top) // 可以設(shè)置為ele.top+200 查看懶加載效果 if (ele.top > 0 && ele.top < clietH) { //從data-url中取出真實的圖片地址賦值給scr item.setAttribute('src', item.getAttribute('data-url')) } }) } </script> </body> </html>
3.3 intersectionObserve() intersectionObserve()
新的API,針對元素的可見時間進行監(jiān)聽。由于可見(visible)的本質(zhì)是,目標(biāo)元素與視口產(chǎn)生一個交叉區(qū),所以這個 API 叫做"交叉觀察器"。
var io = new IntersectionObserver(callback, option);
IntersectionObserver
是瀏覽器原生提供的構(gòu)造函數(shù),接受兩個參數(shù):callback
是可見性變化時的回調(diào)函數(shù),option
是配置對象(該參數(shù)可選)。
構(gòu)造函數(shù)的返回值是一個觀察器實例。實例的observe
方法可以指定觀察哪個 DOM 節(jié)點。
// 開始觀察 io.observe(document.getElementById('example')); // 停止觀察 io.unobserve(element); // 關(guān)閉觀察器 io.disconnect();
上面代碼中,observe
的參數(shù)是一個 DOM 節(jié)點對象。如果要觀察多個節(jié)點,就要多次調(diào)用這個方法。
io.observe(elementA); io.observe(elementB);
callack參數(shù)
目標(biāo)元素的可見性變化時,就會調(diào)用觀察器的回調(diào)函數(shù)callback
。
一般會觸發(fā)兩次:1.目標(biāo)元素剛剛進入視口(開始可見),2.完全離開視口(開始不可見)。
callback
函數(shù)的參數(shù)是一個數(shù)組,每個成員都是一個IntersectionObserverEntry
對象。
IntersectionObserverEntry 對象
提供目標(biāo)元素的信息,一共有六個屬性。
- time:可見性發(fā)生變化的時間,是一個高精度時間戳,單位為毫秒
- target:被觀察的目標(biāo)元素,是一個 DOM 節(jié)點對象
- rootBounds:根元素的矩形區(qū)域的信息,getBoundingClientRect()方法的返回值,如果沒有根元素(即直接相對于視口滾動),則返回null
- boundingClientRect:目標(biāo)元素的矩形區(qū)域的信息
- intersectionRect:目標(biāo)元素與視口(或根元素)的交叉區(qū)域的信息
- intersectionRatio:目標(biāo)元素的可見比例,即intersectionRect占boundingClientRect的比例,完全可見時為1,完全不可見時小于等于0
所以可以通過判斷intersectionRatio屬性是否處于(0,1)來判斷元素的可見性
代碼實現(xiàn)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } img { margin-top:400px; width: 250px; display: block; } </style> </head> <body> <img src="img/1pxImg.png" data-url="img/1.jpg"> <img src="img/1pxImg.png" data-url="img/2.jpg"> <img src="img/1pxImg.png" data-url="img/3.jpg"> <img src="img/1pxImg.png" data-url="img/4.jpg"> <img src="img/1pxImg.png" data-url="img/5.jpg"> <script> var imgs = document.getElementsByTagName('img') // 觀察器實例 let io = new IntersectionObserver((entires) =>{ entires.forEach(item => { // 原圖片元素 let oImg = item.target if (item.intersectionRatio > 0 && item.intersectionRatio <= 1) { oImg.setAttribute('src', oImg.getAttribute('data-url')) } }) }) // 給每一個圖片設(shè)置觀察器 Array.from(imgs).forEach(element => { io.observe(element) }); </script> </body> </html>
總結(jié)
到此這篇關(guān)于前端圖片懶加載的原理與3種實現(xiàn)方式的文章就介紹到這了,更多相關(guān)前端圖片懶加載實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript代碼實現(xiàn)禁止右鍵、禁選擇、禁粘貼、禁shift、禁ctrl、禁alt
這篇文章主要介紹了JavaScript代碼實現(xiàn)禁止右鍵、禁選擇、禁粘貼、禁shift、禁ctrl、禁alt,需要的朋友可以參考下2015-11-11uni.getLocation和wx.getLocation方法調(diào)用無效也不返回失敗的解決方案
這篇文章主要給大家介紹了關(guān)于uni.getLocation和wx.getLocation方法調(diào)用無效也不返回失敗的解決方案,文中通過實例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-04-04基于JavaScript實現(xiàn)圖片點擊彈出窗口而不是保存
這篇文章主要介紹了基于JavaScript實現(xiàn)圖片點擊彈出窗口而不是保存的相關(guān)資料,需要的朋友可以參考下2016-02-02