先寫下標題盗似,今晚寫這個博客~
昨晚改項目BUG改的太晚了拄氯,實在沒空寫该窗,只能放在今天寫咯~
最近寫的小項目正好遇到需要懶加載和函數(shù)節(jié)流,查了資料了解了一下原理“柘現(xiàn)在寫個博客總結一下查找到的資料并簡單用JS實現(xiàn)一下挑豌,以便以后查閱~
注:本文未沒有介紹預加載與函數(shù)防抖,主要是暫時未遇上這兩個需求墩崩,日后有機會再補充氓英!
懶加載
什么是懶加載呢?
- 懶加載又稱作延遲加載(英語:lazyload)鹦筹,通俗的說一下就是訪問一個網(wǎng)頁的時候铝阐,先把圖片的路徑換成固定的一張圖讓其先占好位置(即占位圖)。當頁面滾動到這張圖片出現(xiàn)在頁面可視區(qū)域內時立即設置圖片的真實路徑铐拐,這便是懶加載饰迹。
為什么要用懶加載呢?
- 簡單來說是為了優(yōu)化網(wǎng)頁余舶,加快網(wǎng)頁載入速度啊鸭。說具體一點呢就是頁面里的內容實在太多了,比如隨便打開淘寶匿值、京東等網(wǎng)上商城的網(wǎng)頁赠制,頁面往下滾你可以看到有非常多的圖片,這些圖片大小不一,有的幾百k有的可能要1m了钟些。如果當用戶進入頁面時將這些圖片全部都展示出來烟号,那可能耗時太長,用戶等的黃花菜都涼了政恍。汪拥。。
- 所以可以使用懶加載先展示在瀏覽器可視區(qū)域內的圖片篙耗,加快頁面載入速度~
那接下來我就簡單用JS實現(xiàn)一下懶加載迫筑,代碼如下:
// 先給頁面內所有需要懶加載的圖片賦予'lazyload'的類屬性
// 然后把圖片正確的地址放在'data-src'屬性中,如<img data-src="http://xxx.jpg">
let images = document.querySelectorAll('.lazyload') // 查找所有包含lazyload類屬性的標簽
let imgs = [].slice.call(images) // images是一個偽數(shù)組(對象)宗弯,將images轉為真的數(shù)組
// let imgs = Arrary.from(images) 功能與上面一樣脯燃,為ES6語法
let onscroll = function(){
if(imgs.length === 0){ return window.removeEventListener('scroll', onscroll)}
// 判斷imgs這個數(shù)組是否為空,如果為空就代表頁面內沒有需要懶加載的圖片蒙保,刪除監(jiān)聽滾動的事件
imgs.filter( (img)=> { img.classList.contains('lazyload') })
// 過濾掉imgs數(shù)組中不包含類名為'lazyload'的標簽
imgs.forEach((img)=>{
if(inViewport(img)){
loadImage(img) // 如果此圖片出現(xiàn)在視口內就設置圖片的真實路徑
}
})
}
window.addEventListener('scroll', onscroll) // 監(jiān)聽滾動事件辕棚,當滾動時觸發(fā)onscroll
window.dispatchEvent(new Event('scroll'))
// 這行代碼作用是讓瀏覽器自動執(zhí)行一下滾動事件,因為如果載入頁面時瀏覽器自動沒有執(zhí)行滾動事件邓厕,那么此時在視口內的圖片都沒有真實的圖片地址
function inViewport(img){
let { top, left, bottom, right } = img.getBoundingClientRect()
// 調用getBoundingClientRect()這個API逝嚎,讀取當前圖片上下左右各邊距離視口頂部和視口左邊的值,并賦值給相應變量(這里使用的是ES6語法)
let vpHeight = document.documentElement.clientHeight // 獲取視口高度
let vpWidth = document.documentElement.clientWidth // 獲取視口寬度
return (( top > 0 && top < vpHeight || bottom > 0 && bottom < vpHeight ) &&
(left > 0 && left < vpWidth || right > 0 && right < vpWidth ))
// 這行代碼返回布爾值详恼,圖片在視口內返回true懈糯,不在視口內返回false
}
function loadImage(img){
let image = new Image()
// 創(chuàng)建一個image對象
image.src = img.dataset.src
// 讀取img的'data-src'屬性,將圖片真實地址賦給image的src屬性单雾,相當于給瀏覽器緩存了這張真實的圖片
image.onload = function(){
img.src = image.src
// 當瀏覽器加載緩存的圖片時,將圖片真實地址放到此img標簽內她紫,那此img標簽的真實圖片便可直接展示出來
img.classList.remove('lazyload') // 刪除img標簽的'lazyload'類屬性
}
}
函數(shù)節(jié)流
什么是函數(shù)節(jié)流呢硅堆?
- 這里先說一下什么是節(jié)流:比如你家的水龍頭開到最大檔,那水龍頭里的水會嘩嘩的流下來贿讹,但是如果你把水龍頭擰緊直到水以水滴的形式流出渐逃,那你就會發(fā)現(xiàn)每隔一段時間才會有一滴水流出
- 函數(shù)節(jié)流(英語:throttle)也就是設定一個執(zhí)行的周期,前一次調用動作到當前調用動作的時間間隔大于或等于設定的執(zhí)行周期時就執(zhí)行該動作(如果時間間隔小于設定的執(zhí)行周期時民褂,就等時間到達設定的執(zhí)行周期再執(zhí)行動作)茄菊,然后進入下一個周期。
為什么要用函數(shù)節(jié)流呢赊堪?
- 主要是為了限制函數(shù)的執(zhí)行頻率面殖,用于優(yōu)化函數(shù)觸發(fā)頻率過高而導致響應速度跟不上觸發(fā)頻率,出現(xiàn)bug哭廉、延遲脊僚、卡頓等現(xiàn)象。
那接下來我就簡單用JS實現(xiàn)一下函數(shù)節(jié)流遵绰,代碼如下:
function throttle(func, wait){
// 設置一個名為throttle的函數(shù)辽幌,此函數(shù)可接受兩個參數(shù)增淹,一個參數(shù)為執(zhí)行函數(shù),另一個參數(shù)為執(zhí)行周期
let prev, timer
// 聲明兩個變量乌企,一個為前一次調用動作的時間虑润,一個為計時器
return function fn(){
// 返回名為'fn'的函數(shù)
let curr = Date.now()
// 獲取當前時間
let diff = curr - prev
// 獲取前一次調用動作到當前調用動作的時間間隔
if(!prev || diff >= wait){
func()
// 如果調是第一次用動作或時間間隔大于等于執(zhí)行周期,則執(zhí)行所傳入的函數(shù)
prev = curr // 將當前時間賦值給前一次調用動作的時間
}else if(diff < wait){
clearTimeout(timer) // 如果時間間隔小于執(zhí)行周期(即在時間間隔內又觸發(fā)了一次事件)加酵,就清空原先的定時器
timer = setTimeout(fn, wait - diff) // 設置一個新的定時器拳喻,等時間到達設定的執(zhí)行周期再執(zhí)行函數(shù)'fn'
}
}
}
結語:以上就是我根據(jù)查找的資料總結實現(xiàn)的懶加載與函數(shù)節(jié)流。如果其中有問題虽画,麻煩在評論中指出舞蔽。謝謝~