原生JS實(shí)現(xiàn)圖片懶加載之頁(yè)面性能優(yōu)化
在項(xiàng)目開(kāi)發(fā)中,我們往往會(huì)遇到一個(gè)頁(yè)面需要加載很多圖片的情況。我們可以一次性加載全部的圖片,但是考慮到用戶有可能只瀏覽部分圖片。所以我們需要對(duì)圖片加載進(jìn)行優(yōu)化,只加載瀏覽器窗口內(nèi)的圖片,當(dāng)用戶滾動(dòng)時(shí),再加載更多的圖片。這種加載圖片的方式叫做圖片懶加載,又叫做按需加載或圖片的延時(shí)加載。這樣做的好處是:1.可以加快頁(yè)面首屏渲染的速度;2.節(jié)約用戶的流量。
一.實(shí)現(xiàn)思路
1.圖片img標(biāo)簽自定義一個(gè)屬性data-src來(lái)存放真實(shí)的地址。
2.當(dāng)滾動(dòng)頁(yè)面時(shí),檢查所有的img標(biāo)簽,判斷是否出現(xiàn)在事業(yè)中,如果出現(xiàn)在視野中,繼續(xù)進(jìn)行判斷,看齊是否被加載過(guò)了,如果沒(méi)有加載,那就進(jìn)行加載。
判斷圖片元素是否處于瀏覽器視野中的示意圖(手繪):
二.根據(jù)思路完成代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>原生js實(shí)現(xiàn)圖片懶加載</title> <style> *{ margin: 0; padding: 0; box-sizing: border-box; } ul{ overflow: hidden; list-style: none; } li{ float: left; width: 50%; height: 200px; padding: 10px; } li img{ display: inline-block; width: 100%; height: 100%; } </style> </head> <body> <div class="container"> <ul> <li><img src="http://cdn.jirengu.com/book.jirengu.com/img/1.jpg" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/1.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/2.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/3.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/4.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/5.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/6.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/7.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/8.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/9.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/10.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/11.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/12.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/13.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/14.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/15.jpg"></li> <li><img src="" alt="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/16.jpg"></li> </ul> </div> <script> // window綁定滾動(dòng)事件 window.addEventListener('scroll',function(){ // 遍歷所有的img標(biāo)簽 Array.prototype.slice.apply(document.getElementsByTagName('li')).forEach((li)=>{ let img=li.getElementsByTagName('img')[0]; // 判斷當(dāng)前img是否出現(xiàn)在了視野中 // 判斷當(dāng)前img是否被加載過(guò)了 if(checkShow(img) && !isLoaded(img)){ loadImg(img); } }) }); // 判斷img是否出現(xiàn)瀏覽器視野中 function checkShow(img) { let scrollTop=document.documentElement.scrollTop; // 頁(yè)面向上滾動(dòng)的高度 let windowHeight=window.innerHeight; //瀏覽器自身高度 let offsetTop=img.offsetTop; //目標(biāo)標(biāo)簽相對(duì)于document的高度 return (offsetTop > scrollTop && offsetTop <(windowHeight + scrollTop)); } // 判斷是否已經(jīng)加載過(guò) function isLoaded(img) { return img.getAttribute('src')===img.getAttribute('data-src'); } // 加載圖片 function loadImg(img) { img.setAttribute('src',img.getAttribute('data-src')); } </script> </body> </html>
好了,在瀏覽器中運(yùn)行一下,第一次進(jìn)頁(yè)面如果不滾動(dòng)滾輪的話什么也看不到,所以第一次進(jìn)頁(yè)面需要調(diào)用checkShow(),處于視野中的圖片也加載出來(lái)。
在代碼最后加上:
// 第一次進(jìn)頁(yè)面加載處于視野中的圖片 Array.prototype.slice.apply(document.getElementsByTagName('li')).forEach((li)=>{ let img=li.getElementsByTagName('img')[0]; // 判斷當(dāng)前img是否出現(xiàn)在了視野中 // 判斷當(dāng)前img是否被加載過(guò)了 if(checkShow(img) && !isLoaded(img)){ loadImg(img); } })
此時(shí)我們發(fā)現(xiàn)判斷加載視野中的圖片代碼存在重復(fù),直接封裝成一個(gè)新的方法lazyRenderImg();
// window綁定滾動(dòng)事件 window.addEventListener('scroll',function(){ // 遍歷所有的img標(biāo)簽 lazyRenderImg(); }); function lazyRenderImg(){ Array.prototype.slice.apply(document.getElementsByTagName('li')).forEach((li)=>{ let img=li.getElementsByTagName('img')[0]; // 判斷當(dāng)前img是否出現(xiàn)在了視野中 // 判斷當(dāng)前img是否被加載過(guò)了 if(checkShow(img) && !isLoaded(img)){ loadImg(img); } }) } // 第一次進(jìn)頁(yè)面加載處于視野中的圖片 lazyRenderImg();
三.性能優(yōu)化
問(wèn)題:window.scroll
方法頁(yè)面只要一滾動(dòng)就會(huì)觸發(fā)里面的方法,對(duì)性能影響很大
解決方法:當(dāng)頁(yè)面停止?jié)L動(dòng)的時(shí)候,再去執(zhí)行頁(yè)面中的方法,類似與函數(shù)節(jié)流(throttle)
Tips:函數(shù)節(jié)流:等時(shí)間間隔執(zhí)行函數(shù), 讓一個(gè)函數(shù)不要執(zhí)行得太頻繁,減少一些過(guò)快的調(diào)用來(lái)節(jié)流。
// window綁定滾動(dòng)事件 let timer; window.addEventListener('scroll',function(){ console.log('scroll') // 遍歷所有的img標(biāo)簽 if(timer){ clearTimeout(timer) } timer=setTimeout(()=>{ console.log('lazyRenderImg...'); lazyRenderImg(); },300);
通過(guò)打印的日志發(fā)現(xiàn)當(dāng)滾動(dòng)停止后才執(zhí)行lazyRenderImg
方法的,確實(shí)減少了不必要調(diào)用lazyRenderImg
的次數(shù)。
以上所述是小編給大家介紹的原生JS實(shí)現(xiàn)圖片懶加載之頁(yè)面性能優(yōu)化,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
JavaScript中十種一步拷貝數(shù)組的方法實(shí)例詳解
JavaScript中我們經(jīng)常會(huì)遇到拷貝數(shù)組的場(chǎng)景,但是都有哪些方式能夠來(lái)實(shí)現(xiàn)呢,我們不妨來(lái)梳理一下,感興趣的朋友跟隨小編一起看看吧2019-04-04微信小程序--特定區(qū)域滾動(dòng)到頂部時(shí)固定的方法
這篇文章主要介紹了微信小程序--特定區(qū)域滾動(dòng)到頂部時(shí)固定的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04JavaScript XML和string相互轉(zhuǎn)化實(shí)現(xiàn)代碼
兩個(gè)小function實(shí)現(xiàn)XML和string相互轉(zhuǎn)化,需要的朋友可以參考下。2011-07-07用函數(shù)模板,寫一個(gè)簡(jiǎn)單高效的 JSON 查詢器的方法介紹
本篇文章小編將為大家介紹,用函數(shù)模板,寫一個(gè)簡(jiǎn)單高效的 JSON 查詢器的方法介紹,需要的朋友可以參考一下2013-04-04js監(jiān)聽(tīng)元素是否出現(xiàn)在可視區(qū)域詳解(IntersectionObserver)
這篇文章主要給大家介紹了關(guān)于js監(jiān)聽(tīng)元素是否出現(xiàn)在可視區(qū)域(IntersectionObserver)的相關(guān)資料, IntersectionObserver是一個(gè)JavaScript API,用于監(jiān)測(cè)一個(gè)元素與其父元素或視窗的交叉狀態(tài),需要的朋友可以參考下2024-06-06