懶加載(Lazy-Load)娇豫。它是針對圖片加載時機的優(yōu)化:在一些圖片量比較大的網(wǎng)站(比如電商網(wǎng)站首頁掐禁,或者團購網(wǎng)站、小游戲首頁等)漏益,如果我們嘗試在用戶打開頁面的時候,就把所有的圖片資源加載完畢深胳,那么很可能會造成白屏、卡頓等現(xiàn)象铜犬,因為圖片真的太多了舞终,一口氣處理這么多任務(wù),瀏覽器做不到把⒒敛劝!
目的
懶加載 的目的是當頁面的圖片進入到用戶的可視范圍之內(nèi)在加載圖片的一種優(yōu)化方式。
可以增加首屏加載的速度纷宇,畢竟夸盟,用戶點開頁面的瞬間,呈現(xiàn)給他的只是首屏像捶,我們只要把首屏的資源圖片加載處理就可以了上陕,至于下面的圖片桩砰,當用戶下滑當當前位置的時候,在加載出來也是沒問題的释簿,對于性能壓力也小了亚隅,用戶體驗也沒有變差。
原理
在頁面初始化的時候庶溶,
<img>
圖片的src
實際上是放在data-src
屬性上的煮纵,當元素處于可視范圍內(nèi)的時候,就把data-src
賦值給src
屬性偏螺,完成圖片加載行疏。
// 在一開始加載的時候
<img data-src="http://xx.com/xx.png" src="" />
// 在進入可視范圍內(nèi)時
<img data-src="http://xx.com/xx.png" src="http://xx.com/xx.png" />
<div>使用背景圖來實現(xiàn),原理也是一樣的套像,把background-image
放在酿联,在可視范圍時,就把data-src
賦值給src
屬性凉夯,完成圖片加載货葬。
// 在一開始加載的時候
<div
data-src="http://xx.com/xx.png"
style="background-image: none;background-size: cover;"
></div>
// 在進入可視范圍內(nèi)時
<div
data-src="http://xx.com/xx.png"
style="background-image: url(http://xx.com/xx.png);background-size: cover;"
></div>
實現(xiàn)一個懶加載
基于上面的實現(xiàn)思路,自己實現(xiàn)一個懶加載劲够。
新建一個 index.html
中震桶,為這些圖片預置 img
標簽:
<head>
<style>
.img {
width: 200px;
height: 200px;
background-color: gray;
margin-bottom: 20px;
}
.pic {
width: 100%;
height: 100%;
}
</style>
</head>
<!-- 圖片來自網(wǎng)絡(luò),侵刪征绎。 -->
<body>
<div class="container">
<div class="img">
<!-- 注意我們并沒有為它引入真實的src -->
<img
class="pic"
alt="加載中"
data-src="https://tse1-mm.cn.bing.net/th/id/OIP.8OrEFn_rKe82kqAWFjTuMwHaEo?pid=Api&rs=1"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://ssl.tzoo-img.com/images/tzoo.94911.0.910013.seoul-nami.jpg?width=1080"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://tse4-mm.cn.bing.net/th/id/OIP.ZitgAuABnwkrGn4lid2ZmQHaEK?pid=Api&rs=1"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="http://pic34.photophoto.cn/20150315/0034034862056002_b.jpg"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="http://img.mp.sohu.com/upload/20170724/32d4409f34194b029ed287abf1c99b70_th.png"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://pic6.wed114.cn/20180829/2018082910075991913520.jpg"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://tse4-mm.cn.bing.net/th/id/OIP.PZdPKj3sXEX2jLrepx3MUwHaEo?pid=Api&rs=1"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://pic6.wed114.cn/20180829/2018082910075831439349.jpg"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://pic6.wed114.cn/20180829/2018082910075468043336.jpg"
/>
</div>
<div class="img">
<img
class="pic"
alt="加載中"
data-src="https://tse2-mm.cn.bing.net/th/id/OIP.CRYz5Bv4vylsMh83G4CsLgHaFj?pid=Api&rs=1"
/>
</div>
</div>
</body>
在懶加載的實現(xiàn)中蹲姐,有兩個關(guān)鍵的數(shù)值:一個是當前可視區(qū)域的高度,另一個是元素距離可視區(qū)域頂部的高度人柿。
當前可視區(qū)域的高度柴墩,在現(xiàn)代瀏覽器及 IE9 以上的瀏覽器中,可以使用window.innerHeight
屬性獲取凫岖,在低版本的 IE 中使用document.documentElment.clientHeight
獲取江咳,這里我們兼容兩種情況:
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
而元素距離可視區(qū)域頂部的高度,這里我們用 getBoundingClientRect()
方法來獲取返回元素的大小和相對于尺寸的位置哥放,對于該 API歼指,MDN 的解釋是:
Element.getBoundingClientRect() 方法返回元素的大小及其相對于視口的位置。
返回的屬性中有一個相對于可視區(qū)域頂部的高度也就是top
屬性甥雕,剛好就是我們需要的元素距離頂部的距離踩身。
這樣,兩個屬性就都得到了社露。
我們利用當前可視區(qū)域的高度大于等于元素距離可視區(qū)域頂部的高度就可以確定挟阻,該元素是否已經(jīng)進入到了可視范圍:
<script>
// 獲取所有的圖片標簽
const imgs = document.getElementsByTagName("img");
// 獲取可視區(qū)域的高度
const viewHeight =
window.innerHeight || document.documentElement.clientHeight;
// num用于統(tǒng)計當前顯示到了哪一張圖片,避免每次都從第一張圖片開始檢查是否露出
let num = 0;
function lazyload() {
console.log("滾動...");
for (let i = num; i < imgs.length; i++) {
// 用可視區(qū)域高度減去元素頂部距離可視區(qū)域頂部的高度
let distance = viewHeight - imgs[i].getBoundingClientRect().top;
// 如果可視區(qū)域高度大于等于元素頂部距離可視區(qū)域頂部的高度,說明元素露出
if (distance >= 0) {
// 給元素寫入真實的src附鸽,展示圖片
imgs[i].src = imgs[i].getAttribute("data-src");
// 前i張圖片已經(jīng)加載完畢脱拼,下次從第i+1張開始檢查是否露出
num = i + 1;
}
}
}
// 防抖函數(shù)
function debounce(fn, delay = 500) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.call(this, args);
}, delay);
};
}
// 是的頁面初始化是加載首屏圖片
window.onload = lazyload;
// 監(jiān)聽Scroll事件,為了防止頻繁調(diào)用拒炎,使用防抖函數(shù)優(yōu)化一下
window.addEventListener("scroll", debounce(lazyload, 600), false);
</script>
小結(jié)
- 先收集到頁面中所有的
img
(也可以用class
)挪拟。 - 獲取到視圖高度,計算顯示的
img
击你,避免重復賦值src
玉组。 - 當滑動向下滑動鼠標,會觸發(fā)
onScroll
事件(防抖)丁侄,然后觸發(fā)計算是否賦值src
惯雳。