對(duì)于一個(gè)有多個(gè)圖片的網(wǎng)站來說,訪問的時(shí)候不應(yīng)該直接加載所有圖片,而是應(yīng)該只講瀏覽器窗口內(nèi)的圖片進(jìn)行加載。當(dāng)滾動(dòng)的時(shí)候,在加載更多的圖片。叫做圖片的懶加載。
我們可以通過給img自定義一個(gè)新屬性,來存儲(chǔ)圖片真實(shí)的src地址,當(dāng)需要加載的時(shí)候,再將這個(gè)真實(shí)的地址賦給src,進(jìn)行圖片加載。
整體思路:
所以大體的思路為:
- 設(shè)置個(gè)data-src(自定義一個(gè)屬性)來存放真實(shí)地址
- 當(dāng)滾動(dòng)頁面時(shí),檢查所有的img標(biāo)簽,看是否出現(xiàn)在視野中,如果已經(jīng)出現(xiàn)在了視野中,那繼續(xù)再進(jìn)行判斷,看其是否已經(jīng)被加載過了,如果還沒有被加載過,那就進(jìn)行加載。
想到這一步,整體的大概思路可以寫為:
$(window).on('scroll',function () {//當(dāng)頁面滾動(dòng)的時(shí)候綁定事件
$('.container img').each(function () {//遍歷所有的img標(biāo)簽
if (checkShow($(this)) && !isLoaded($(this)) ){
// 需要寫一個(gè)checkShow函數(shù)來判斷當(dāng)前img是否已經(jīng)出現(xiàn)在了視野中
//還需要寫一個(gè)isLoaded函數(shù)判斷當(dāng)前img是否已經(jīng)被加載過了
loadImg($(this));//符合上述條件之后,再寫一個(gè)加載函數(shù)加載當(dāng)前img
}
})
})
function checkShow($img) { // 傳入一個(gè)img的jq對(duì)象
}
function isLoaded ($img) {
}
function loadImg ($img) {
}
判斷目標(biāo)標(biāo)簽是否出現(xiàn)在視野中:
此時(shí),判斷目標(biāo)標(biāo)簽是否已經(jīng)出現(xiàn)在視野中的思路為:
分析標(biāo)簽出現(xiàn)在頁面中的兩個(gè)臨界狀態(tài):
- 當(dāng)頁面向上滾動(dòng),一直滾到首先出現(xiàn)在頁面的下邊緣的時(shí)候,此時(shí)有頁面向上滾動(dòng)的距離,加上瀏覽器自身的高度,就等于目標(biāo)標(biāo)簽本身在頁面中距離頁面頂部的距離。
- 頁面接著向上滾,當(dāng)頁面出現(xiàn)在了瀏覽器的上邊沿的時(shí)候,此時(shí)頁面向上滾的高度,就等于目標(biāo)標(biāo)簽本身在頁面中距離頁面頂部的距離
那么可以checkShow函數(shù)可以寫為:
.offset()方法允許我們檢索一個(gè)元素 (包含其 border 邊框,不包括 margin) 相對(duì)于文檔(document)的當(dāng)前位置。.offset()返回一個(gè)包含top 和 left屬性的對(duì)象 。表示相對(duì)于頂部或者左邊的坐標(biāo)。
function checkShow($img) { // 傳入一個(gè)img的jq對(duì)象
var scrollTop = $(window).scrollTop(); //即頁面向上滾動(dòng)的距離
var windowHeight = $(window).height(); // 瀏覽器自身的高度
var offsetTop = $img.offset().top; //目標(biāo)標(biāo)簽img相對(duì)于document頂部的位置
if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2個(gè)臨界狀態(tài)之間的就為出現(xiàn)在視野中的
return true;
}
return false;
}
判斷目標(biāo)標(biāo)簽是否已經(jīng)被加載過:
function isLoaded ($img) {
return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已經(jīng)加載過了
}
加載目標(biāo)標(biāo)簽
function loadImg ($img) {
$img.attr('src',$img.attr('data-src')); // 加載就是把自定義屬性中存放的真實(shí)的src地址賦給src屬性
}
優(yōu)化代碼
那么此時(shí)的代碼就能實(shí)現(xiàn)大體功能了,此時(shí)完整代碼為:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>圖片懶加載-簡(jiǎn)單</title>
<script src="../jquery-3.2.1.min.js"></script>
<style>
ul,li{
list-style:none;
}
.container{
width: 600px;
margin: 0 auto;
}
.container li{
float: left;
margin: 10px 10px;
}
.container li img{
width: 240px;
height: 180px;
}
p{
float: left;
}
</style>
</head>
<body>
<ul class="container">
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/1.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/2.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/3.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/4.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/5.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/6.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/7.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/8.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/9.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/10.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/11.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/12.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/13.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/14.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/15.jpg" /></a></li>
<li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/16.jpg" /></a></li>
</ul>
<script>
$(window).on('scroll',function () {//當(dāng)頁面滾動(dòng)的時(shí)候綁定事件
$('.container img').each(function () {//遍歷所有的img標(biāo)簽
if (checkShow($(this)) && !isLoaded($(this)) ){
// 需要寫一個(gè)checkShow函數(shù)來判斷當(dāng)前img是否已經(jīng)出現(xiàn)在了視野中
//還需要寫一個(gè)isLoaded函數(shù)判斷當(dāng)前img是否已經(jīng)被加載過了
loadImg($(this));//符合上述條件之后,再寫一個(gè)加載函數(shù)加載當(dāng)前img
}
})
})
function checkShow($img) { // 傳入一個(gè)img的jq對(duì)象
var scrollTop = $(window).scrollTop(); //即頁面向上滾動(dòng)的距離
var windowHeight = $(window).height(); // 瀏覽器自身的高度
var offsetTop = $img.offset().top; //目標(biāo)標(biāo)簽img相對(duì)于document頂部的位置
if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2個(gè)臨界狀態(tài)之間的就為出現(xiàn)在視野中的
return true;
}
return false;
}
function isLoaded ($img) {
return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已經(jīng)加載過了
}
function loadImg ($img) {
$img.attr('src',$img.attr('data-src')); // 加載就是把自定義屬性中存放的真實(shí)的src地址賦給src屬性
}
</script>
</body>
</html>
首先有個(gè)明顯的問題,目前頁面上,第一次進(jìn)來的時(shí)候如果不滾動(dòng)滾輪的話什么都看不到,想修復(fù)這個(gè)問題,可以先進(jìn)行一次頁面檢查,調(diào)用checkShow(),然后頁面上在視野中的標(biāo)簽就會(huì)被加載,然后再進(jìn)行監(jiān)聽window的scroll事件。
// 先進(jìn)行一次檢查
$('.container img').each(function () {
if (checkShow($(this)) && !isLoaded($(this)) ){
loadImg($(this));
}
})
$(window).on('scroll',function () {
$('.container img').each(function () {
if (checkShow($(this)) && !isLoaded($(this)) ){
loadImg($(this));
}
})
})
但是此時(shí)代碼有重復(fù)的,進(jìn)行優(yōu)化。將重復(fù)的代碼塊寫成一個(gè)新的函數(shù)。進(jìn)行替換。
// 先進(jìn)行一次檢查
lazyRender();
$(window).on('scroll',function () {
lazyRender();
})
function lazyRender () {
$('.container img').each(function () {
if (checkShow($(this)) && !isLoaded($(this)) ){
loadImg($(this));
}
})
}
代碼優(yōu)化已經(jīng)很好了,對(duì)于性能的優(yōu)化:
$(window).on('scroll',function () {}這個(gè)事件鼠標(biāo)滾動(dòng)的時(shí)候觸發(fā)次數(shù)非常多。對(duì)性能影響大,優(yōu)化思路是當(dāng)鼠標(biāo)滾輪停止?jié)L動(dòng)的時(shí)候,再去判定是否存在在視野中,而不是滾動(dòng)過程中一直觸發(fā)。
// 先進(jìn)行一次檢查
lazyRender();
//為了不在滾輪滾動(dòng)過程中就一直判定,設(shè)置個(gè)setTimeout,等停止?jié)L動(dòng)后再去判定是否出現(xiàn)在視野中。
var clock; //這里的clock為timeID,
$(window).on('scroll',function () {
// lazyRender();
if (clock) { // 如果在300毫秒內(nèi)進(jìn)行scroll的話,都會(huì)被clearTimeout掉,setTimeout不會(huì)執(zhí)行。
//如果有300毫秒外的操作,會(huì)得到一個(gè)新的timeID即clock,會(huì)執(zhí)行一次setTimeout,然后保存這次setTimeout的ID,
//對(duì)于300毫秒內(nèi)的scroll事件,不會(huì)生成新的timeID值,所以會(huì)一直被clearTimeout掉,不會(huì)執(zhí)行setTimeout.
clearTimeout(clock);
}
clock = setTimeout(function () {
console.log('運(yùn)行了一次');
lazyRender();
},300)
})