文章代碼可在這裏下載.css
先不給圖片設置 src
屬性值, 當圖片進入瀏覽器窗口的時,給圖片的src
屬性賦值, 開始請求圖片並渲染至屏幕。html
data-src
屬性來保存正確的圖片連接,將src
屬性設置爲空(或默認圖片連接)src
屬性賦予正確的值如今有一個須要解決的問題:怎麼知道圖片是否在視窗以內呢?git
能夠這樣判斷:當圖片的底部和頁面的頂部的距離小於視窗的底部和頁面的頂部的距離時就能夠認爲圖片已經進入視窗了。這樣提及來有些繞,用圖片來看看會更清晰。api
當視窗在下拉過程當中其底部低於圖片的底部時,就認爲圖片已經要加載了: 數組
爲方便說明,先實現單張圖片的懶加載,使用 JQuery庫來完成。瀏覽器
JQuery的api中能夠獲取到視窗的高度、視窗頂部和頁面頂部的距離,兩者相加就是視窗底部和頁面頂部的距離;一樣的,也能夠得到圖片包裹層的高度和它的頂部到頁面頂部的距離,相加就是圖片包裹層底部到頁面頂部的距離。網絡
將以上兩者比較,就能夠肯定圖片是否須要被加載。app
DOM結構框架
<div class="wrap-single">
<img src="" data- src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg">
</div>
複製代碼
圖片初始樣式ui
img {
width: 100%;
display: none;
/* 加載以前先隱藏 */
}
複製代碼
JQuery代碼
let $wrap = $('.wrap-single'),
img = $wrap.children('img'),
$window = $(window);
$window.on('load scroll', function(e) { // 同時監聽 加載完成和滾動 事件
if(img.attr('is-loaded') === 'true') { // 當圖片被打上已加載的標記時再也不進行請求
return ;
}
// 獲取圖片容器自己的高度 + border-top距離body 頂部的高度
let wrapBottomDist= $wrap.outerHeight() + $wrap.offset().top;
// 獲取視窗自己的高度 + 視窗頂部距離 body 頂部的高度
let windowBottomDist = $window.outerHeight() + $window.scrollTop();
// 判斷圖片容器是否已在視窗之中
if(wrapBottomDist <= windowBottomDist) {
// 如果,則取得真實圖片地址並設置給 src 屬性
let realSrc = img.attr('data-src');
img.attr('src', realSrc);
// 當圖片加載完成時,設置圖片顯示,並標記圖片已經加載完成
img.on('load', () => {
img.css('display', 'block');
img.attr('is-loaded', true); // 利用自定義屬性打上加載完成的標記
});
}
});
複製代碼
效果以下:
可見只有當圖片徹底進入窗口時纔會開始請求圖片,同時從右側能夠看出當圖片進入窗口是纔會發出對圖片連接的請求。
在有了單張圖片懶加載的基礎後,實現多張圖片的懶加載就容易多了。直接給出代碼吧,代碼中有詳細的註釋:
DOM 結構
<div class="wrap">
<h1>A Lazy Load Demo</h1>
<div class="img-wrapper">
<img src="" data-src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg">
</div>
<!-- 省略多行一樣的代碼 -->
<div class="img-wrapper">
<img src="" data-src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg">
</div>
</div>
複製代碼
JQuery 代碼
let $boxes = $('.img-wrapper'),
$window = $(window),
imgs = [], // 保存每張圖片的對象
wrapBottomDist = []; // 保存每張圖片底部與 body 頂部的距離
$boxes.each((index, item) => { // 處理數組 imgs 和 wrapBottomDist
let $item = $(item);
imgs.push($item.children('img'));
wrapBottomDist.push($item.outerHeight() + $item.offset().top); // 獲取圖片容器自己的高度 + border-top距離body 頂部的高度
});
function lazy() { // 事件處理程序
// 判斷是否須要繼續執行
if(!wrapBottomDist.length || !wrapBottomDist[wrapBottomDist.length - 1]) {
return ;
}
// 獲取視窗自己的高度 + 視窗頂部距離 body 頂部的高度
let windowBottomDist = $window.outerHeight() + $window.scrollTop();
// 一次判斷每張圖片是否已經進入視窗
wrapBottomDist.forEach((pos, index) => {
if(pos < windowBottomDist) {
let img = imgs[index];
img.attr('src', img.attr('data-src'));
img.on('load', () => {
img.css('display', 'block');
});
wrapBottomDist[index] = undefined; // 將已經進入視窗的項進行標記
}
});
}
$window.on('load scroll', lazy); // 註冊事件處理程序
複製代碼
效果
若有錯誤,敬請指出,謝謝~