無限滾動的優(yōu)化方案(二):懶加載實(shí)現(xiàn)

之前對預(yù)加載的實(shí)現(xiàn)方案做了介紹,這一篇文章主要是我對圖片的懶加載的實(shí)現(xiàn)的一個(gè)總結(jié)。主要包括:

  1. 視區(qū)檢測
  2. 圖片懶加載及延遲顯示

實(shí)例簡介

之前一直對單頁應(yīng)用有興趣,所以自己寫了一個(gè)前端路由,相關(guān)的文章見這里,這個(gè)單頁應(yīng)用采取hash的方式實(shí)現(xiàn)路由。最終的實(shí)例頁面見這里。倉庫在這里是一個(gè)經(jīng)典的單頁應(yīng)用。要做優(yōu)化的就是主頁的信息滾動。這些信息通過ajax從服務(wù)器端獲取,這里為了方便,服務(wù)器端會一直返回?cái)?shù)據(jù),哪怕是重復(fù)的。頁面如下:

Paste_Image.png

懶加載

可以看到,頁面中,每一條消息都有一個(gè)圖片,這個(gè)時(shí)候,如果在dom剛剛建立好,就對所有的圖片進(jìn)行加載,此時(shí),占用過多的下載通道(我的是每次顯示10條消息,接近頁面底部時(shí)會預(yù)加載),會導(dǎo)致后面的信息加載速度變慢,用戶體驗(yàn)不好。而圖片懶加載是指:圖片進(jìn)入用戶視野才會進(jìn)行加載,而不是在dom樹一構(gòu)建好就進(jìn)行加載。 道理很簡單,但是我在實(shí)現(xiàn)的過程中還是碰到了一些問題,下面就是我的實(shí)現(xiàn)方案。

懶加載實(shí)現(xiàn)方案

總體變量以及函數(shù)定義

//記錄圖片的序號
let num = 0;
//記錄是否正在獲取數(shù)據(jù),保證請求只做一次
let state = true;
//記錄圖片數(shù)據(jù),index,src,height三個(gè)關(guān)鍵元素
var img_data =[];
//記錄表單的距離頁面頂端的距離
var list_height = 0;

function getH(obj) {
   //獲得對象距離頁面頂端的距離
}
function lazy_load(){
  //圖片懶加載的實(shí)現(xiàn)函數(shù)
}
function getInfo(){
   //從服務(wù)器端獲取商家發(fā)布的新信息
   //并向圖片數(shù)據(jù)中存放圖片信息 
}
function main(){
  //主函數(shù)
  //實(shí)現(xiàn)初始化
  //滾動事件的綁定等
}

獲取元素相對頁面頂部的高度

這個(gè)函數(shù)其實(shí)不難,主要涉及到目標(biāo)元素下面幾個(gè)屬性:

  1. node.offsetTop:相對其父元素的位置
  2. node.offsetParent: 元素的父元素
    所以,要獲取元素相對頁面頂部的高度,其實(shí)只需要進(jìn)行遞歸或者迭代就能實(shí)現(xiàn),這里采用迭代實(shí)現(xiàn):
function getH(obj) {
    var h = 0;
    while (obj) {
        h += obj.offsetTop;
        obj = obj.offsetParent;
    }
    return h;
}

數(shù)據(jù)的緩存

程序中,通過Ajax從服務(wù)器獲取數(shù)據(jù),每次最多獲取10條,在dom中,img標(biāo)簽最開始并不指定src,src存儲在ajax獲取到的信息中,我將其存入:img_data中,與它一同存入的,還有該圖片的高度height,第幾條信息index。
這里的height,可以采用上面的迭代得到,但是每次迭代對資源損耗比較大,事實(shí)上也是沒有必要的,因?yàn)槊織l信息是固定的高度,所以根據(jù)其是第幾條信息,再獲取一個(gè)list相對頁面頂部的高度,就能得到圖片相對頁面頂部的高度。我這里每個(gè)圖片(100px)算上間隙(40px)就是140px,只需要獲取整個(gè)列表相對頂部的高度,就能得到每個(gè)圖片相對頁面頂部的距離。
程序中大概像這樣子:

img_data.push({
        index:(num),
        height:list_height+(140)*(num),
        src:data.src,
        loaded:false //定期清理,加載之后的圖片信息進(jìn)行清除,降低內(nèi)存使用 
      })

視區(qū)的檢測

圖片是否落在用戶視區(qū),需要用到以下高度:

  1. height1:document.body.scrollTop:瀏覽器滾動的高度
  2. height2:document.body.clientHeight:可視區(qū)域的高度
  3. height3:node.height:也就是之前獲取到的元素相對頁面頂部的高度(并不是相對可視區(qū)域的頂部)
    當(dāng)height3>heihgt1且height3<height2+height1的時(shí)候,可以認(rèn)為這個(gè)元素是出現(xiàn)在用戶視區(qū)的,從而將img_data的src賦值給這個(gè)塊的img標(biāo)簽,當(dāng)圖片加載好之后,opacity配合transition實(shí)現(xiàn)動態(tài)的浮現(xiàn)(據(jù)說,人感覺這樣加載的速度更快)。這一塊大致的代碼如下:
function lazy_load(){
var height1 = document.body.scrollTop+document.body.clientHeight;
  img_data.forEach(function(item){
    if(!item.loaded && item.height>document.body.scrollTop-100 && item.height < height1){
      var img = document.querySelector("img[img-index='"+item.index+"']");
//選擇該圖片
      if(img){
        img.src = item.src;
        item.loaded = true; //下面對img_data進(jìn)行filter的函數(shù),減少內(nèi)存消耗
        img.onload = function(){
          img.style.opacity = 1;//配合transition可以實(shí)現(xiàn)一個(gè)漸入的效果
        }
        img.onerror = function(){
          img.style.opacity = 1;
          img.src = '/failed.jpg';//加載失敗,
        }
      }
    }
  img_data = img_data.filter(function(item){
    return !item.loaded;
  })
}

滾動函數(shù)的綁定

直接將上述函數(shù)和window.onscroll進(jìn)行綁定是不太理想的,因?yàn)闈L動函數(shù)的觸發(fā)頻率很高,而視區(qū)的檢測如果每次滾動都進(jìn)行檢測,那么,一方面造成性能上的損失,一方面,似乎所有的圖片都能被檢測到出現(xiàn)在了視區(qū),從而導(dǎo)致所有的圖片都會被加載,并沒有起到懶加載的作用。所以在這里,我使用了函數(shù)消抖,原理也不難,網(wǎng)上的實(shí)現(xiàn)很多,這里給出我的實(shí)現(xiàn):

method.debounce = function(func,delay){
  var timer;
  return function(){
    var args = arguments;
    var context = this;
    clearTimeout(timer);
    timer = setTimeout(function(){
      func.apply(this,args);
    },delay);
  }
}

和上述lazy_load結(jié)合,進(jìn)行綁定,代碼如下:

var lazy_event = method.debounce(lazy_load,500);//此處500ms可以適當(dāng)縮小
method.addevent(window,'scroll',lazy_event);

和消抖函數(shù)結(jié)合之后,用戶的滾動不會觸發(fā)lazy_load,只有當(dāng)用戶停止?jié)L動才會執(zhí)行l(wèi)azy_load,從而達(dá)到圖片懶加載的效果。

總結(jié)

這次無限滾動,我實(shí)現(xiàn)了兩種方案:預(yù)加載與圖片懶加載,配合消抖和節(jié)流以及緩存,能夠很好的提升頁面性能。希望面試的時(shí)候能用上吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,107評論 1 92
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,828評論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,104評論 4 61
  • 昨夜 雨聲陣陣,寒風(fēng)瑟瑟 雷雨交加、閃電轟鳴,讓人顫栗害怕 冷氣逼人,讓人感覺冷是從心中鉆出來的! 這樣的夜 最適...
    流年時(shí)光_fe16閱讀 627評論 1 2
  • 《堅(jiān)持一定就有收獲!》 2017年 3月19日 星期日 晴今天是讀經(jīng)二年零342天,我的日記大樓蓋到1...
    66e1ba940d65閱讀 363評論 0 0

友情鏈接更多精彩內(nèi)容