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