1. 程式人生 > >預載入+監聽圖片資源載入製作進度條

預載入+監聽圖片資源載入製作進度條

這兩天遇到一個新需求:一個一鏡到底的h5動畫。因為功能的特殊性,就要求我們提前監聽頁面的靜態圖片是否全部載入完畢。即處理預載入。

總結下來,下次這種需求需要提前注意以下幾點:

一、圖片而不是背景圖

本來,我所用到的圖都是用背景圖製作的(因為非介面返回的圖片都要求用背景圖)。

但是監聽靜態圖片時,後來發現所用的方法監聽不到背景圖,所以改成了圖片。

這是一個坑。

二、獲取新載入的圖片:Img.load()

1、要監聽圖片我們要先獲取到頁面中的所有圖片:jq的方法:find()

var MyImg = $(body).find('img');

很簡單的解決了這個問題。

MyImg得到的是目標元素中的所有圖片的集合。

2、然後我們要遍歷所有的圖片,好判斷是否載入完畢:

依然是jq的方法:each()

MyImg.each(function(){
    //在這裡實現 分別對每一個圖片的圖片載入結果 的監聽。
})

3、然後說如何監聽圖片載入:

萬年青jq方法:load()

Img.load(function(){
    // 回撥裡,執行載入完畢一個的記錄處理
})

還好這次用的jq寫的程式碼,省了不少事。

為了記錄圖片載入完畢的個數,我在全域性設定一個變數:

var sum = 0;

並準備一個方法讓sum累加

function sumAdd(){
    sum++;
}

然後load方法的回撥裡,呼叫sumAdd

MyImg.load(()=>{
      // 用於新載入的圖片
      sumAdd(1);
});

最後頁面載入完成後成功得到 sum=7;(本次案例頁面7張圖)

三、獲取快取的圖片:Img.complete

now

圖片載入是能控制了,但是為什麼我一重新整理他又監聽不到了?

哦!原來頁面載入完畢後重新整理,再展示的圖片都是快取的圖,而load又監聽不到快取的圖。

要了我的老命了。

於是我又找,什麼方法能監聽快取的圖啊?目標鎖定了js裡的img.complete。注意劃重點是js的屬性

。所以這裡使用上要注意,因為我獲取的dom物件是jq的,要轉成js的再調complete屬性,於是程式碼直接是:

if(MyImg[0].complete){
    // 用於快取圖片
    sumAdd();
}

有了之前準備的sumAdd函式做接應,快取圖片的個數也能計算出來了。

至此,一個非常簡易又簡陋的監聽就完成了。

題外話

之前不是這麼做的,而是load方法裡累加load的個數,complete裡累加快取的個數。

在電腦上測試,兩者河井互不犯,相安無事。

但是到手機上發現,會有6張快取圖1張載入圖,導致下邊要說的載入進度計算錯誤,先是變成70%,又變回20%。

後來才改成這兩種情況都累加到一處了。

四、預載入進度計算並展示

好了,現在需求升級。

為了友好的使用者體驗,你在後臺載入圖片的時候,使用者不能只看到一個載入中,等半天不知道到底有沒有反應。

所以我們要給使用者一個及時的反饋,就要獲取圖片載入的進度。

思路就是 :

載入進度 = 已載入圖片資源個數/總的圖片資源個數*100+'%';

有了公式,又有之前我們準備的sum(當前載入個數),這個載入進度輕而易舉就能得到了:

let progress = Math.ceil(sum/7*100);

7是當前頁面中圖片的總個數。而Math.ceil向上取整是為了在除不盡的時候不會出現小數點或99.9999%的情況。當然為了控制萬一超過100的情況,只需要保險設定一下:

progress>=100?100:progress

如果載入進度想做成進度條效果,只需要把得到的progress值賦給進度條的寬度即可。至於進度條怎麼做,看我這篇博文。css案例 - 評分效果的星星✨外衣

五、數字動畫效果:animate()

後來我又想,進度條旁邊加數字展示豈不是更好?

而作為一個有些許追求的程式設計師,我又不想直接做成數字是多少就生硬切換成多少的效果。

我想做逐漸變化的數字動畫效果

這就要另一個方法上場了。

對,沒錯,還是jq的方法 - animate()方法:

利用其step屬性達到動畫逐幀改變的效果,也就是文字從1累加漸變成100,而不是生硬的跳轉為100。

這個方法的用法是這樣的:

$('#loadingTxts').animate({count: progress},{
    duration: 350,
    step: function() {
        if(isNaN(this.count)){
            this.count = 0;
            return;
        }
        let boxText = Math.ceil(Number(this.count));
        if(boxText >= 100){
            boxText = 100;
            //接下來執行預載入完畢,頁面開始展示
            ...
        }
        $('#loadingTxts').text(boxText+'%');// 文字展示
        $('.progress').css('width',boxText+'%'); // 進度條寬度設定
    }
});    

一個坑接一個坑,最後我們被折磨得沒了生氣的力氣。

大致參考程式碼:

$(function () {
  let nameLink = 'https://www.test.com/test/dist/images/',
    nameArr = ['1', '2', '3', '4', '5', '6', '7'],
    myImgs = $('.baby-box').find('img'),
    downAndCache = 0;

  function progressAni(i){
    downAndCache += i;
    let progreVal = Math.ceil(downAndCache/nameArr.length*100);
    // 文字-單值變化動畫
    $('#txtsBox').animate({
      count: progreVal
    },{
      duration: 350,
      step: function() {
        if(isNaN(this.count)){
          this.count = 0;
          return;
        }
        let numberTxt = Math.ceil(Number(this.count));
        if(numberTxt >= 100){
          numberTxt = 100;
          $('.loading').fadeOut();
        }
        $('#txtsBox').text(numberTxt+'%');
        $('#progressBox').css('width',numberTxt+'%');
      }
    });
  }
  myImgs.each(function(a){
    let Img = $(this);
    if(Img[0].complete){
      // 用於快取圖片
      progressAni(1);
    }
    Img.load(()=>{
      // 用於新載入的圖片
      progressAni(1);
    });
    Img.error(function() {
      // 圖片載入失敗,可以選擇替換圖片
      console.log(Img.attr('src'));
      Img.attr('src',nameLink + nameArr[a] + '.jpg');
    });
  });
});

2018-09-13 17:32:28