JavaScript懶加載與預(yù)加載原理與實(shí)現(xiàn)詳解
1、懶加載
1.1、什么是懶加載
懶加載也可以叫做延遲加載,當(dāng)訪問一個(gè)頁面的時(shí)候,先把img元素伙食其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣只需要請(qǐng)求一次,俗稱占位圖);
只有當(dāng)圖片出現(xiàn)在瀏覽器的可視區(qū)域內(nèi)時(shí),才這只圖片真正的路徑,讓圖片顯示出來,這就是圖片懶加載。
1.2、為什么要使用懶加載
當(dāng)頁面很多,內(nèi)容很豐富的時(shí)候,頁面很長(zhǎng),圖片較多,比如各個(gè)商城頁面,要是頁面載入就一次性加載完畢,就需要等很長(zhǎng)的時(shí)間
1.3、懶加載的優(yōu)點(diǎn)
按需加載,頁面加載速度快,節(jié)約流量,用戶體驗(yàn)感好,減少服務(wù)器壓力
1.4、懶加載的原理
頁面中的img元素,如果沒有src屬性, 瀏覽器就不會(huì)發(fā)出請(qǐng)求去下載圖片,只有通過javascript設(shè)置了圖片路徑,瀏覽器才會(huì)發(fā)送請(qǐng)求。
懶加載的原理就是先在頁面中把所有的圖片統(tǒng)一使用一張占位圖進(jìn)行占位,把真正的路徑存在元素的"data-url"(這個(gè)名字起個(gè)自己認(rèn)識(shí)好記的就行)屬性里,要用的時(shí)候就取出來放在src里面
1.5、懶加載的實(shí)現(xiàn)步驟
- 首先,不要將圖片地址放到src屬性中,而是放到其它屬性(data-origina)中。
- 頁面加載完成后,判斷圖片是否在用戶的視野內(nèi),如果在,則將data-original屬性中的值取出存放到src屬性中
1.6、懶加載的實(shí)現(xiàn)方式
<ul> <li><img src="../img/loading.gif" alt="" data-src="../img/1.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/2.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/3.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/4.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/5.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/6.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/7.jpg"></li> <li><img src="../img/loading.gif" alt="" data-src="../img/8.jpg"></li> </ul>
方式1:通過 元素距離頂部的高度 - 滾動(dòng)條滾動(dòng)的高度 < =窗口可視化區(qū)域高度 進(jìn)行判斷;
/*元素距離頂部的高度-頁面被卷去的高度<=瀏覽器可視區(qū)域的高度 如果條件滿足,就可以替換圖片的src屬性 */ //獲取圖片 const imgArr = document.querySelectorAll("img"); //初始化執(zhí)行 lazyLoad(); //監(jiān)聽用戶是否滾動(dòng)滾動(dòng)條,但是這高觸發(fā)事件,所以需要結(jié)合節(jié)流優(yōu)化 window.addEventListener("scroll", throttle(lazyLoad, 2000)); function lazyLoad() { imgArr.forEach(item => { //1、獲取圖片距離頂部的高度 const imgOffsetTop = item.offsetTop; //2、獲取瀏覽器的可視區(qū)域的高度 const wHeight = window.innerHeight; //3、獲取頁面被卷去的高度 const scrollHeight = document.documentElement.scrollTop; //判斷圖片是否將要出現(xiàn) if (imgOffsetTop - scrollHeight <= wHeight) { item.src = item.getAttribute("data-src"); } }) } //節(jié)流 function throttle(fun, time = 250) { let lastTime = 0;//最后一次執(zhí)行的時(shí)間 return function (...args) { const now = new Date().getTime();//獲取當(dāng)前的時(shí)間 if (now - lastTime >= time) { fun(); lastTime = now; } } }
方式2:getBoundingClientRect()
- 獲取元素位置, 這個(gè)方法沒有參數(shù)
- 用于獲得頁面中某個(gè)元素的左,上, 右和下分別相對(duì)瀏覽器視窗的位置。
- 是DOM元素到瀏覽器可視范圍的距離(不包含文檔卷起的部分)
- 該函數(shù)返回一個(gè)0bject對(duì)象, 該對(duì)象有6個(gè)屬性: top, lef, right, bottom , width, height;
const imgArr = document.querySelectorAll("img"); //初始化執(zhí)行 lazyLoad() //監(jiān)聽用戶是否滾動(dòng)滾動(dòng)條,但是這高觸發(fā)事件,所以需要結(jié)合節(jié)流優(yōu)化 //監(jiān)聽用戶是否滾動(dòng)滾動(dòng)條,但是這高觸發(fā)事件,所以需要結(jié)合節(jié)流優(yōu)化 window.addEventListener("scroll", throttle(lazyLoad, 2000)); function lazyLoad() { imgArr.forEach(item => { //獲取圖片和頂部的高度 const imgTop = item.getBoundingClientRect().top; //獲取瀏覽器可視化區(qū)域高度 const wHeight = window.innerHeight; //圖片和頂部的高度小于瀏覽器窗口可視化區(qū)域的高度 if (imgTop <= wHeight) { //getAttribute獲取自定義屬性 // item.src = item.getAttribute("data-src"); //也可以使用dataset來獲取自定義屬性的值 item.src = item.dataset.src; } }) } //節(jié)流 function throttle(fun, time = 250) { let lastTime = 0;//最后一次執(zhí)行的時(shí)間 return function (...args) { const now = new Date().getTime();//獲取當(dāng)前的時(shí)間 if (now - lastTime >= time) { fun(); lastTime = now; } } }
方式3:IntersectionObserver(callback)構(gòu)造函數(shù)
callback回調(diào)觸發(fā)兩次,看見了觸發(fā),看不見也觸發(fā)。
實(shí)例有兩個(gè)方法:
- observe給元素添加觀察
- unobserve取消對(duì)元素觀察
const callback = (res) => { //res是一個(gè)數(shù)組,所以還需要遍歷 console.log(res); res.forEach(item => { //isIntersecting是否在可視區(qū)域展示 if (item.isIntersecting) { //獲取圖片的自定義屬性并賦值給src item.target.src = item.target.dataset.src; //替換為真是src地址后取消對(duì)它的觀察 observe.unobserve(item.target); } }) } //1、實(shí)例化構(gòu)造函數(shù) const observe = new IntersectionObserver(callback); const imgArr = document.querySelectorAll("img"); //遍歷所有的圖片,給每個(gè)圖片添加觀察 imgArr.forEach(item => { //觀察圖片 observe.observe(item) })
2、預(yù)加載
2.1、什么是預(yù)加載
資源預(yù)加載是另一個(gè)性能優(yōu)化技術(shù),我們可以使用該技術(shù)來預(yù)先告知瀏覽器某些資源可能在將來會(huì)被使用到。預(yù)加載簡(jiǎn)單來說就是將所有所需的資源提前請(qǐng)求加載到本地,這樣后面在需要用到時(shí)就直接從緩存取資源。
2.2、為什么要使用預(yù)加載
在網(wǎng)頁全部加載之前,對(duì)一些主要內(nèi)容進(jìn)行加載,以提供給用戶更好的體驗(yàn),減少等待的時(shí)間。否則,如果一個(gè)頁面的內(nèi)容過于龐大,沒有使用預(yù)加載技術(shù)的頁面就會(huì)長(zhǎng)時(shí)間的展現(xiàn)為一片空白,直到所有內(nèi)容加載完畢。
2.3、實(shí)現(xiàn)預(yù)加載的方法
<div> <p></p> <img src="../img/1.jpg" alt=""> </div> <script type="text/javascript"> const imgArr = ["../img/2.jpg", "../img/3.jpg", "../img/4.jpg", "../img/5.jpg", "../img/6.jpg", "../img/7.jpg"] const img = document.querySelector("img"); const p = document.querySelector("p"); //定義默認(rèn)的index的值 let index = 0; p.innerHTML = `實(shí)現(xiàn)預(yù)加載的效果,我是第${index + 1}張圖片`; img.addEventListener("click", (e) => { if (index < imgArr.length) { img.src = imgArr[index]; index++; p.innerHTML = `實(shí)現(xiàn)預(yù)加載的效果,我是第${index + 1}張圖片`; if (index < imgArr.length) { //切換圖片后,同時(shí)讓瀏覽器提前加載下一張圖片 preLoad(imgArr[index]) } } else { confirm("沒有圖片了") } }, false) //調(diào)用預(yù)加載函數(shù),頁面一開始就加載數(shù)組的第一個(gè)元素 preLoad(imgArr[0]) //定義預(yù)加載函數(shù) function preLoad(src) { //當(dāng)圖片失去焦點(diǎn)后 img.addEventListener("load", () => { //創(chuàng)建一個(gè)新的img標(biāo)簽 const imgNew = document.createElement("img"); //給img標(biāo)簽添加src屬性為我們傳進(jìn)來的src imgNew.src = src; }) } </script>
到此這篇關(guān)于JavaScript懶加載與預(yù)加載原理與實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)JS懶加載與預(yù)加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Document.body.scrollTop的值總為零的快速解決辦法
這篇文章主要介紹了Document.body.scrollTop的值總為零的解決方法的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06微信小程序van-field中的left-icon屬性自定義實(shí)現(xiàn)過程
在小程序中,我們是用 Vant 組件庫時(shí),常常會(huì)用到 van-field 輸入框控件,今天我將跟大家分享的是 van-field 輸入框控件中的 left-icon 屬性的自定義怎么實(shí)現(xiàn),感興趣的朋友一起看看吧2023-08-08bootstrap插件treeview實(shí)現(xiàn)全選父節(jié)點(diǎn)下所有子節(jié)點(diǎn)和反選功能
這篇文章主要為大家詳細(xì)介紹了bootstrap插件treeview實(shí)現(xiàn)全選父節(jié)點(diǎn)下所有子節(jié)點(diǎn)、反選功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07ES6知識(shí)點(diǎn)整理之String字符串新增常用方法示例
這篇文章主要介紹了ES6知識(shí)點(diǎn)整理之String字符串新增常用方法,結(jié)合實(shí)例形式分析了ES6字符串String includes,startsWith,endsWith等方法相關(guān)使用技巧,需要的朋友可以參考下2019-07-07js setTimeout()函數(shù)介紹及應(yīng)用以倒計(jì)時(shí)為例
setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式,下面有個(gè)倒計(jì)時(shí)的示例,需要的朋友可以學(xué)習(xí)下2013-12-12關(guān)于javascript DOM事件模型的兩件事
DOM事件模型的兩件事:事件捕捉(Event Capture)的實(shí)現(xiàn)問題以及IE的高級(jí)事件處理模型的問題。2010-07-07js實(shí)現(xiàn)隨屏幕滾動(dòng)的帶緩沖效果的右下角廣告代碼
這篇文章主要介紹了js實(shí)現(xiàn)隨屏幕滾動(dòng)的帶緩沖效果的右下角廣告代碼,涉及javascript基于數(shù)學(xué)運(yùn)算及定時(shí)函數(shù)動(dòng)態(tài)操作頁面元素的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09