什么是圖片懶加載
圖片的懶加載就是在頁面打開的時候,不要一次性全部顯示頁面所有的圖片,而是只顯示當前視口內的圖片,一般在移動端使用(PC端主要是前端分頁或者后端分頁)。
為什么需要懶加載
對於一個頁面加載速度影響最大的因素之一就是圖片資源,如果一個頁面圖片太多(比如某寶,某東等),整個頁面的圖片大小可以到達幾百兆,即使在百兆寬帶,全部下載的話,也需要上十秒的時間,這對於用戶耐心的考驗是巨大的,更別說網絡差的地方了。
因此,懶加載是必須要做的,對於頁面未在可視區域內顯示的圖片先不做加載處理,只加載第一映入眼簾的圖片,由於可視區域顯示的圖片少,加載速度就會大大提升,用戶體驗也會更好。
而且,用戶可能只翻看一兩頁就退出了,剩下未查看的圖片也就不需要加載了。這也相當於節省了帶寬資源。
懶加載實現原理
由於瀏覽器會自動對頁面中的img標簽的src屬性發送請求並下載圖片。因此,通過html5自定義屬性data-xxx
先暫存src的值,然后在需要顯示的時候,再將data-xxx
的值重新賦值到img的src屬性即可。
實現代碼
這里模擬兩種情況:
情況一
1、前端已經獲取到所有的圖片了,現在需要將這些圖片以懶加載的形式展示。
例子如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>懶加載Demo1</title>
<style>
.box {
width: 600px;
margin: 0 auto;
}
img {
width: 100%;
}
</style>
</head>
<body>
<div class="box">
<img src="./images/1.jpg" alt="">
<img src="./images/2.jpg" alt="">
<img src="./images/3.jpg" alt="">
<img src="./images/4.jpg" alt="">
<img src="./images/5.jpg" alt="">
<img src="./images/6.jpg" alt="">
<img src="./images/7.jpg" alt="">
<img src="./images/8.jpg" alt="">
<img src="./images/9.jpg" alt="">
<img src="./images/10.jpg" alt="">
</div>
</body>
</html>
可以看出,10張圖片是一次性全部加載完的。
下面改造成懶加載:
首先將頁面上的圖片的 src 屬性設為空字符串,而圖片的真實路徑則設置在data-src屬性中。
當頁面滾動的時候需要去監聽scroll
事件,在scroll事件的回調中,判斷我們的懶加載的圖片判斷是否出現在視口內,如果出現在視口內,則將data-src
賦值到src。
如何判斷一個元素是否在視口內呢?
通過getBoundingClientRect()
方法來獲取元素的大小以及位置。這個方法返回一個名為ClientRect的DOMRect
對象,包含了top、right、botton、left、width、height這些值。
隨着滾動條的向下滾動,bound.top
會越來越小,也就是圖片到可視區域頂部的距離越來越小,當bound.top <= clientHeight
時,圖片的上沿應該是位於可視區域下沿的位置的臨界點,再滾動一點點,圖片就會進入可視區域。
function isInSight(el) {
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
//如果只考慮向下滾動加載
//const clientWidth = window.innerWeight;
return bound.top <= clientHeight + 100; // 這里有個+100是為了提前加載。
}
源代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>懶加載Demo1</title>
<style>
.box {
width: 600px;
margin: 0 auto;
}
img {
width: 100%;
height: 600px;
}
</style>
</head>
<body>
<div class="box">
<img src="" alt="" data-src="./images/1.jpg">
<img src="" alt="" data-src="./images/2.jpg">
<img src="" alt="" data-src="./images/3.jpg">
<img src="" alt="" data-src="./images/4.jpg">
<img src="" alt="" data-src="./images/5.jpg">
<img src="" alt="" data-src="./images/6.jpg">
<img src="" alt="" data-src="./images/7.jpg">
<img src="" alt="" data-src="./images/8.jpg">
<img src="" alt="" data-src="./images/9.jpg">
<img src="" alt="" data-src="./images/10.jpg">
</div>
</body>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
$(function () {
// 第一次需要先加載一次
lazyLoad();
$(window).scroll(lazyLoad);
function isInSight(el) {
const bound = el.getBoundingClientRect();
const clientHeight = $(window).height(); // 可視區高度
return bound.top <= clientHeight + 100; // 這里有個+100是為了提前加載。
}
function lazyLoad() {
$.each($('.box img'), (index,item)=>{
if(isInSight(item)) {
$(item).attr('src', $(item).attr('data-src'));
}
});
}
});
</script>
</html>
當向下滑動的時候,從Network面板可以看到,剩下的圖片是一個個加載的。
可能有人疑問為什么第一次加載了4張,而不是3張?
因為我在判斷是否在可視區內加了100 , return bound.top <= clientHeight + 100;
可以提前加載一張圖片。
注意:一定要設置圖片的高度。
提示:src的賦值在js原生和jq是不同的,混用的話不會生效。
用js原生方法:
document.getElementById("imageId").src = "xxxx.jpg";
用Jquery方法:$("#imageId").attr("src","xxxx.jpg");
而下面的兩種都不會生效:
$("#imageId").src = "xxxx.jpg";
document.getElementById("imageId").attr("src","xxxx.jpg");
切記!
情況二
2、前端從后端獲取圖片進行展示,后端進行分頁。
思路:當頁面滾動的時候需要去監聽scroll
事件,在scroll事件的回調中,判斷滾動條是否滾動到最底部,如果是,則將將圖片的 src 屬性設置為data-src
的值。
判斷是否滾動到最底部的方法:滾動條到頂部距離 + 可視頁面高度 >= 當前頁面高度
var seeHeight = document.documentElement.clientHeight; // 可視頁面高度
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 滾動條到頂部距離
var bodyHeight = document.body.offsetHeight // 當前頁面高度
然后判斷: scrollTop + seeHeight >= bodyHeight
當滾動條到達底部的時候,獲取后端分頁的數據。
這里使用一個模擬接口來獲取數據: https://www.apiopen.top/meituApi?page=1
page為頁碼數,一次返回20條數據。當page=0時,會隨機返回一頁數據,page>=1時會返回相應頁碼的數據。
源代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>懶加載Demo1</title>
<style>
.box {
width: 600px;
margin: 0 auto;
}
img {
width: 100%;
height: 600px;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
$(function () {
let pageNum = 2; // 因為第一頁沒有圖片,我從第二頁開始的
getImage(pageNum);
$(window).scroll(lazyLoad);
function getImage(pageNum) {
$.ajax({
url:'https://www.apiopen.top/meituApi?page='+pageNum,
type: 'GET',
success(res) {
// 遍歷圖片,將圖片加入div中
if(res.code === 200 && res.data) {
res.data.forEach((item,index)=>{
$('.box').append(`<img src="${item.url}">`);
});
}
},
});
}
function lazyLoad() {
let seeHeight = document.documentElement.clientHeight;
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
let bodyHeight = document.body.offsetHeight;
if((Math.ceil(seeHeight + scrollTop) >= bodyHeight)) { // 向上取整的原因是可能有小數
getImage(++pageNum);
}
}
});
</script>
</html>
當滾動到20張圖的底部的時候,就會發出ajax請求,請求下一頁數據。
至此本文完,有疑問可以在評論區隨時交流哈。