JavaScript實(shí)現(xiàn)圖片懶加載與預(yù)加載的代碼詳解
引言
圖片懶加載與預(yù)加載是前端優(yōu)化中比較常見的方法,也是前端面試中會被問到的問題。懶加載就是當(dāng)你打開一個頁面時,沒有出現(xiàn)在屏幕中的圖片先不加載,等滑到該圖片位置時再加載,而預(yù)加載就是一次性把圖片加載完。
如果不做懶加載和預(yù)加載,瀏覽器的回流重繪很快,而圖片的加載是需要發(fā)送網(wǎng)絡(luò)請求的,當(dāng)圖片一百甚至一千張時,一次性發(fā)很多請求就會導(dǎo)致網(wǎng)絡(luò)的堵塞,影響用戶體驗(yàn),接下來就讓我們來實(shí)現(xiàn)一下懶加載以及預(yù)加載的效果。
懶加載
懶加載原理就是監(jiān)聽屏幕滾動事件,然后判斷圖片是否出現(xiàn)在屏幕內(nèi),等圖片要出現(xiàn)在屏幕內(nèi)再加載??梢允褂胘s中的getBoundingClientRect()方法,獲取元素的集合屬性,打印如下。
<body>
<img src="" data-src="https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF" alt="">
<script>
let img = document.querySelector('img')
let rect = img.getBoundingClientRect() // 獲取元素幾何屬性
console.log(rect);
</script>
</body>

left:左邊框到窗口左邊的距離,right:右邊框到窗口左邊的距離,bottom:下邊框到窗口上邊的距離,top:上邊框到窗口上邊的距離。
然后判斷圖片是否在容器內(nèi),圖片的top小于窗口的高度,圖片的bottom大于0。
為了讓圖片先不展示,就不能把圖片的url放在src屬性上,于是我們可以在img標(biāo)簽中自己定義一個屬性data-src,將圖片地址放進(jìn)去,然后當(dāng)圖片要展示時,令圖片的src等于data-src屬性,展示過后的圖片再移除掉data-src屬性。
<img src="" data-src="https://t7.baidu.com/it/u=17329669972981886582&fm=193&f=GIF" alt="">
<script>
let height = window.innerHeight
function lazyLoad() {
const imgs = document.querySelectorAll('[data-src]')
// console.log(imgs);
for (let i = 0; i < imgs.length; i++) {
let rect = imgs[i].getBoundingClientRect() // 獲取元素的集合屬性
if (rect.bottom > 0 && rect.top < height) {
imgs[i].src = imgs[i].getAttribute('data-src')
imgs[i].onload = function () { // 圖片被瀏覽器加載完畢
imgs[i].src = imgs[i].getAttribute('src')
}
imgs[i].removeAttribute('data-src')
}
}
}
lazyLoad()
window.addEventListener('scroll', lazyLoad)
</script>
當(dāng)然里面的imgs[i].src = imgs[i].getAttribute('data-src')可以換成如下:
// imgs[i].src = imgs[i].getAttribute('data-src')
// imgs[i].onload = function () { // 圖片被瀏覽器加載完畢
// imgs[i].src = imgs[i].getAttribute('src')
// }
// 換成
let newImg = new Image()
newImg.src = imgs[i].getAttribute('data-src') // 讀取 url
newImg.onload = function () { // 圖片被瀏覽器加載完畢
imgs[i].src = newImg.getAttribute('src')
}
目的是為了將圖片的加載過程異步化,以此來減輕主線程的壓力。這是通過創(chuàng)建一個新的Image對象,然后設(shè)置其src屬性來預(yù)加載圖片,一旦圖片加載完成(onload事件觸發(fā)),再將圖片的src屬性設(shè)置到原來的img元素上。
效果如下:

預(yù)加載
用戶一打開頁面,全部圖片先加載,然后后用戶滑動就會非常地絲滑,但是就會導(dǎo)致同一時間加載圖片過多,對服務(wù)器壓力過大。
原理:在加載頁面的同時,創(chuàng)建第二個線程去加載圖片,當(dāng)圖片加載完畢后,將圖片資源交給第一個線程去展示,從而實(shí)現(xiàn)圖片的預(yù)加載。
代碼如下;
<div id="pic"></div>
<script>
let pic = document.getElementById('pic')
let arr = [xxxxx] // 圖片資源
// 創(chuàng)建一個新的線程
const worker = new Worker('worker.js')
// 將數(shù)據(jù)發(fā)送給子線程
worker.postMessage(arr)
</script>
worker函數(shù)是js自帶的一個函數(shù),作用就是創(chuàng)建一個新線程,但是這個新線程不能操作dom結(jié)構(gòu)。這兩個線程可以通信,通過postMessage進(jìn)行通訊。
然后worker.js里面去加載圖片,直接通過http請求去加載資源,回來的是blob類型的文件。
// worker.js self就是worker
self.onmessage = function (e) {
// console.log(e.data); // 傳過來的圖片資源
// 將數(shù)組中的地址資源加載出來
let arr = e.data;
for (let i = 0; i < arr.length; i++) {
let xhr = new XMLHttpRequest();
xhr.open("get", arr[i], true);
xhr.responseType = 'blob' // 文件類型
xhr.send();
xhr.onload = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// console.log(xhr.response);
self.postMessage(xhr.response); //將圖片發(fā)送給主線程
}
}
}
}
然后主線程去接收資源再進(jìn)行渲染;
<body>
<div id="pic"></div>
<script>
let pic = document.getElementById('pic')
let arr = [xxxxx] // 圖片資源
// 創(chuàng)建一個新的線程
const worker = new Worker('worker.js')
// 將數(shù)據(jù)發(fā)送給子線程
worker.postMessage(arr)
// 接收子線程發(fā)送的數(shù)據(jù)
worker.onmessage = function (e) {
console.log(e.data);
const img = new Image()
// console.log(window.URL.createObjectURL(e.data));
img.src = window.URL.createObjectURL(e.data)
pic.appendChild(img)
}
</script>
</body>
window.URL.createObjectURL(e.data)是window自帶的方法,作用就是將blob資源轉(zhuǎn)換成url。
小結(jié)
- 懶加載原理:當(dāng)頁面加載完畢后,判斷在可視區(qū)域內(nèi)的圖片先加載,當(dāng)用戶滾動時,判斷圖片是否進(jìn)入可視區(qū)域,如果進(jìn)入可視區(qū),則將圖片的src替換為真實(shí)圖片路徑,從而實(shí)現(xiàn)懶加載的原理。
- 預(yù)加載原理:在加載頁面的同時,開一個新線程去加載圖片,當(dāng)圖片加載完畢后,將圖片資源交給主線程去展示,從而實(shí)現(xiàn)圖片的預(yù)加載。
以上就是JavaScript實(shí)現(xiàn)圖片懶加載與預(yù)加載的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript圖片懶加載與預(yù)加載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Bootstrap基本組件學(xué)習(xí)筆記之input輸入框組(9)
這篇文章主要為大家詳細(xì)介紹了Bootstrap基本組件學(xué)習(xí)筆記之input輸入框組,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
使用JavaScript下載圖片并保存到本地超詳細(xì)實(shí)例代碼
在JavaScript(JS)中,圖片下載通常涉及到前端與后端的交互,下面這篇文章主要介紹了使用JavaScript下載圖片并保存到本地的相關(guān)資料,文中通過代碼及圖文介紹的非常詳細(xì),需要的朋友可以參考下2025-05-05
Js查找字符串中出現(xiàn)次數(shù)最多的字符及個數(shù)實(shí)例解析
這篇文章主要介紹了Js查找字符串中出現(xiàn)次數(shù)最多的字符及個數(shù) ,本文分為傳統(tǒng)寫法和正則寫法兩種方法給大家介紹了js查找字符串出現(xiàn)次數(shù)最多的字符及個數(shù),非常不錯,感興趣的朋友參考下吧2016-09-09
實(shí)現(xiàn)只能輸入數(shù)字的input不用replace方法
只能輸入數(shù)字在以往都是使用replace方法實(shí)現(xiàn)的,在本文你將學(xué)習(xí)到不使用它依然可以實(shí)現(xiàn),具體代碼如下,感興趣的朋友可以參考下2013-09-09
利用uni-app和uView實(shí)現(xiàn)多圖上傳功能全過程
最近在使用uniapp開發(fā)的微信小程序中使用了圖片上傳功能,下面這篇文章主要給大家介紹了關(guān)于利用uni-app和uView實(shí)現(xiàn)多圖上傳功能的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
完美解決手機(jī)瀏覽器頂部下拉出現(xiàn)網(wǎng)頁源或刷新的問題
下面小編就為大家分享一篇完美解決手機(jī)瀏覽器頂部下拉出現(xiàn)網(wǎng)頁源或刷新的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-11-11
詳解JavaScript 浮點(diǎn)數(shù)運(yùn)算的精度問題
這篇文章主要介紹了詳解JavaScript 浮點(diǎn)數(shù)運(yùn)算的精度問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
javascript html5實(shí)現(xiàn)表單驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了javascript html5實(shí)現(xiàn)表單驗(yàn)證的具體代碼,感興趣的小伙伴們可以參考一下2016-03-03

