為了避免頁面一次性向服務器發送大量請求而造成頁面阻塞,我們需要控制請求數量,按照我們需要的量去加載圖片。
-
懶加載的優點
提高前端性能,按需加載圖片減輕服務器負擔,提高頁面加載速度。
-
懶加載的原理
圖片的加載是依賴於
src
路徑,我們可以設置一個暫存器,把圖片路勁放到暫存器中,當我們需要這個圖片加載顯示時,再把路徑賦值給src
,這樣就能實現按需加載,也就是懶加載。我們通常使用html5中的data-
屬性作為暫存器,例如src
的值默認是正在加載中的GIF,而真正的圖片路徑是保存在data-
中。 -
懶加載的實現
現在很多優秀的插件都能夠實現懶加載的功能,但是不管方法如何,實現原理都是一樣的。
JQuery
(不使用插件)
使用懶加載時,我們的src
的值默認是”正在加載中“的GIF,data-lazyload
是自定義屬性,用於存放圖片真實路徑。如下面的代碼。
<img src="loading.gif" data-lazyload="img.jpg">
我們首先要知道什么時候應該加載圖片,什么時候不需要加載?
對於用戶來說,看得到的地方才需要加載,看不到的地方加載了也是白白浪費資源。所以我們知道,在可視區域中,我們才需要加載圖片。
如何判斷圖片是否在可是區域?我們可以利用元素的偏移高度,對比設備寬度加上滾動條高度來判斷該元素是否處於可視區域中。
上圖中,offsetTop
是圖片元素的偏移高度,window.height()
是設備的高度,scrollTop
是滾動條與頂部的距離,因為滾動條在頂部,所以值為0。
當offsetTop
大於window.height() + scrollTop
時,圖片就在可視區域之外。此時我們可以拉動滾動條,讓文檔向上移動,圖片漸漸出現在可視區域之中。
圖片元素的offsetTop
基本不變,如果設備高度加上滾動條與頂部的距離大於或者等於圖片元素的偏移高度,我們就說它是在可視區域當中。所以有如下表達式:
img.offset().top <= window.height() + window.scrollTop(); // => true/false
接下來借助jQuery來實現
定義十張圖片
./loading.gif
——加載中圖片
data-lazyload
——自定義屬性,存放圖片路徑
<div class="img"> <img src="./loading.gif" data-lazyload="https://dpic3.tiankong.com/67/cn/QJ6226943363.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/zt/sg/QJ6235849453.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/ul/ac/QJ6479383109.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic2.tiankong.com/1z/kb/QJ6401246638.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/ut/zj/QJ6634256101.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic.tiankong.com/09/jh/QJ6635714192.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic3.tiankong.com/6k/i5/QJ6727412259.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic2.tiankong.com/av/fc/QJ6872601378.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic.tiankong.com/37/1u/QJ7100086664.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/jt/7l/QJ7100510973.jpg@!350h"> </div>
JavaScript
1 // 監聽滾動條事件 2 $(window).on('scroll', () => { 3 // 設置延時函數,防止加載過快,減輕服務器負擔;為了效果明顯,設置兩秒延時 4 setTimeout(() => { 5 // 執行獲取圖片函數 6 getImg(); 7 },2000); 8 }) 9 10 // 獲取圖片函數 11 function getImg() { 12 // 遍歷圖片元素 13 $('.img img').each((index, item) => { 14 // 判斷每一個圖片元素是否在可視區域 15 if($(item).offset().top <= $(window).height() + $(window).scrollTop()) { 16 // 把暫存器data-lazyload的值賦值給img標簽的src 17 $(item).attr('src', $(item).attr('data-lazyload')) 18 } 19 }) 20 }
上面的代碼就是懶加載的實現方法,但是仍然有些瑕疵,比如延時函數沒有及時清除、遍歷圖片元素時把已經加載的圖片也一起遍歷了、代碼沒有分模塊等
下面進一步優化得到
引用:https://www.jianshu.com/p/8e2a73638153
1 // 第一次加載 2 getImg(); 3 4 var clock; // 設置一個延時函數節流 5 6 $(window).on('scroll', () => { 7 if (clock) { 8 // 如果拉動滾動條時,延時函數還未執行完,則清除 9 clearTimeout(clock); 10 } 11 clock = setTimeout(() => { 12 getImg(); 13 }, 2000) 14 }) 15 16 function getImg() { 17 // 返回沒有data-isLoaded的img標簽 18 // [1,2,3].not(1) => 返回不含有1的數組 [2,3] 19 $('.img img').not('[data-isLoading]').each((index,item) => { 20 if(isShow(item)) loading(item); 21 }) 22 } 23 24 function isShow(img) { 25 return $(img).offset().top <= $(window).height() + $(window).scrollTop() 26 } 27 28 function loading(img) { 29 $(img).attr('src', $(img).attr('data-lazyload')); 30 // 為已經加載的圖片加一個標識,上面遍歷圖片的時候就會跳過已經加載了的圖片 31 $(img).attr('data-isLoaded', 1); 32 }
演示
我們可以在控制台中明顯看到,只有三張圖片已經加載,滑動滾動條加載更多的圖片
JQuery
(使用jquery.lazyload
)
引入jQuery
和jquery_lazyload
img
標簽
data-original——圖片地址
<img data-original="https://dpic3.tiankong.com/67/cn/QJ6226943363.jpg@!350h">
JavaScript
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/jquery_lazyload/1.9.3/jquery.lazyload.min.js"></script> <script type="text/javascript"> $(".img img").lazyload({ placeholder : "./loading.gif", //用圖片提前占位 // placeholder,值為某一圖片路徑.此圖片用來占據將要加載的圖片的位置,待圖片加載時,占位圖則會隱藏 effect: "fadeIn", // 載入使用何種效果 // effect(特效),值有show(直接顯示),fadeIn(淡入),slideDown(下拉)等,常用fadeIn threshold: 200, // 提前開始加載 // threshold,值為數字,代表頁面高度.如設置為200,表示滾動條在離目標位置還有200的高度時就開始加載圖片,可以做到不讓用戶察覺 }); </script>
總結:
Vue
中也有類似的插件vue_lazyload
,使用方法也是非常簡單,實現的效果相同。
對比自己手寫一個懶加載,插件明顯較為方便。插件雖然好用,但我覺得先了解其實現原理,再使用插件,會讓你受益匪淺。