js - 預加載+監聽圖片資源加載制作進度條


這兩天遇到一個新需求:一個一鏡到底的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

相同思路的 一段其他的處理方法: 2018-10-26  14:00:21

 1 //加載圖片
 2 var loadImgIndex = 0,
 3     path = 'images/';
 4 exports.loadImg = function(arr,callback){
 5     var len = arr.length,
 6         callback = callback || function(){};
 7     if(!len){
 8         return;
 9     }
10     (function loading(){
11         var img = new Image();
12         img.onload = function(){
13             if(loadImgIndex == len-1){
14                 callback();
15             }else{
16                 loadImgIndex++;
17                 console.log('圖片已經加載:' + Math.floor(loadImgIndex/len*100) + '%');
18                 loading();
19             }
20         }
21         img.src = path + arr[loadImgIndex];
22         img.onerror = function(){
23             console.log('加載失敗');
24             setTimeout(callback,1000);
25         }
26     })();
27 
28 --------------------- 
29 //作者:kongjunchao159 
30 //來源:CSDN 
31 //原文:https://blog.csdn.net/kongjunchao159/article/details/49587573 
32 //版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

還有這個文章,寫的講解也很好。通俗易懂:

 https://blog.csdn.net/ssisse/article/details/51655644?utm_source=blogxgwz0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM