小程序遠(yuǎn)程圖片資源按需預(yù)加載
最近做H5開發(fā)遇到個(gè)問(wèn)題,為了防止頁(yè)面打開時(shí),出現(xiàn)大圖加載緩慢的情況,寫了一個(gè)圖片資源管理器,今天順便實(shí)現(xiàn)了一下小程序版。
特別說(shuō)明一下,小程序由于資源包大小限制,很多圖片資源會(huì)存放到CND圖片服務(wù)器上,為了實(shí)現(xiàn)小程序初始化時(shí)按需加載遠(yuǎn)程圖片資源,實(shí)現(xiàn)了以下加載器,希望能解決部分小程序新人開發(fā)者預(yù)加載圖片的苦惱。
特別強(qiáng)調(diào):
本加載器為初級(jí)版本,暫未研究其他實(shí)現(xiàn)方式,當(dāng)前實(shí)現(xiàn)方式需要在微信公眾平臺(tái)->設(shè)置->downloadFile合法域名,中添加想要加載的圖片所在服務(wù)器合法域名。
原理介紹:
使用小程序自帶API讀取遠(yuǎn)程圖片資源:
wx.getImageInfo({
src: 'images/a.jpg',
success: function (res) {
console.log(res.width)
console.log(res.height)
}
})
這個(gè)接口可以創(chuàng)建圖片組件對(duì)象并返回圖片加載狀態(tài)。
加載器用法:
1、在app.js的同級(jí)目錄下創(chuàng)建一個(gè)ImageSource.js作為圖片資源的路徑管理文件(可以根據(jù)情況改為其他文件名稱)。
2、在utils文件夾下放入ImageLoader.js或ImageLoader.min.js(附件)。
3、根據(jù)需要在對(duì)應(yīng)的文件中創(chuàng)建ImageLoader對(duì)象(看下文)。
使用示例:
1、載入文件:
const ImageLoader = require('./utils/ImageLoader.min.js');
const ImageSource = require('./imageSource.js');
ImageLoader.min.js 為加載器源文件。
imageSource.js 為圖片資源路徑文件。
2、創(chuàng)建ImageLoader對(duì)象。
new ImageLoader({
base: ImageSource.BASE,
source: [ImageSource],
loading: res => {
// 可以做進(jìn)度條動(dòng)畫
console.log(res);
},
loaded: res => {
// 可以加載完畢動(dòng)畫
console.log(res);
}
});
參數(shù)
base : String 圖片資源的基礎(chǔ)路徑 必填 示例: "https://image.example.com/static/images/"
source : Array 需要預(yù)加載的圖片資源 必填 示例: [ImageSource.banners, ImageSource.imageList]
loading : function 圖片加載中的回調(diào)方法 非必填 示例:
loaded : funciton 圖片記載完成后的回調(diào) 非必填 示例:
加載器(ImageLoader.js)源碼:
let base = 0;
let Img = function(src) {
this.src = src;
this.status = false;
this.fail = false;
}
let loop = (o, res) => {
let tem = Object.keys(o);
tem.map(v => {
if (typeof o[v] === 'object') {
loop(o[v], res);
} else {
if(v === 'BASE') {
base = o[v];
} else {
res.push(o[v]);
}
}
});
}
function ImageLoader(obj) {
let arr = []; if(obj.loading) {
this.loadingcallback = obj.loading;
}
if(obj.loaded) {
this.loadedcallback = obj.loaded;
}
if(obj.base) {
base = obj.base
}
this.insert = (item) => {
arr.push(item);
};
this.init = (o) => {
let res = [];
loop(o, res);
console.log(res)
res.map((v) => {
this.insert(new Img(v));
});
this.load();
};
this.load = () => {
this.start = (new Date).getTime();
arr.map((v) => {
let src = base ? base + v.src: v.src;
wx.getImageInfo({
src: src,
success: res => {
v.status = true;
},
fail: err => {
v.fail = true;
}
})
});
let timer = setInterval(() => {
let status = this.isLoaded();
if (status) {
clearTimeout(timer);
}
}, 200);
setTimeout(() => {
clearTimeout(timer);
}, 60000);
};
this.isLoaded = () => {
let status = true,
count = 0,
fail = 0;
arr.map((v) => {
if (!v.status) {
status = false;
} else {
count += 1;
}
if(v.fail) {
status = true;
fail += 1;
}
});
if(status) {
if(this.loadedcallback) {
this.loadedcallback({
status: true,
timecost: (new Date).getTime() - this.start,
success: count,
fail: fail,
totalcount: arr.length
})
}
} else {
if(this.loadingcallback) {
this.loadingcallback({
status: false,
percent: count / arr.length
});
}
}
return status;
};
if(obj.source) {
this.init(obj.source);
}
}
module.exports = ImageLoader
圖片資源路徑文件(imageSource.js)源碼:
module.exports = {
"BASE": "https://img.caibeitv.com/static_project/teacherTest/static/img/",
"single1": "ghost.4449aa4.png",
"single2": "ghost.4449aa4.png",
"single3": "ghost.4449aa4.png",
"single4": "ghost.4449aa4.png",
"pages": {
"index": ["ghost.4449aa4.png", "ghost.4449aa4.png"],
"user": ["ghost.4449aa4.png", "ghost.4449aa4.png"],
"home": ["ghost.4449aa4.png", "ghost.4449aa4.png"],
"login": ["ghost.4449aa4.png", "ghost.4449aa4.png"]
},
"imageList": [
"ghost.4449aa4.png",
"ghost.4449aa4.png",
"ghost.4449aa4.png",
"ghost.4449aa4.png",
"ghost.4449aa4.png"
],
"folders": {
"page1": "ghost.4449aa4.png",
"page2": "ghost.4449aa4.png",
"inner": [
"ghost.4449aa4.png",
"ghost.4449aa4.png"
],
"home": {
"poster": "ghost.4449aa4.png"
}
}
}
說(shuō)明:
BASE 字段必填 根據(jù)自我需要填寫。
其他圖片資源支持:
1、直接key:value形式把圖片路徑寫入,如:
"single1": "ghost.4449aa4.png"
2、類似于pages目錄把每個(gè)頁(yè)面的遠(yuǎn)程資源寫入到對(duì)應(yīng)位置下,方便引用和管理,如:
"pages": {
"index": ["ghost.4449aa4.png", "ghost.4449aa4.png"],
"user": ["ghost.4449aa4.png", "ghost.4449aa4.png"],
"home": ["ghost.4449aa4.png", "ghost.4449aa4.png"],
"login": ["ghost.4449aa4.png", "ghost.4449aa4.png"]
},
3、直接以數(shù)組方式把圖片堆放在一個(gè)數(shù)組里,如:
"imageList": [
"ghost.4449aa4.png",
"ghost.4449aa4.png",
"ghost.4449aa4.png",
"ghost.4449aa4.png",
"ghost.4449aa4.png"
]
4、隨意的資源數(shù)組,對(duì)象嵌套,如:
"folders": {
"page1": "ghost.4449aa4.png",
"page2": "ghost.4449aa4.png",
"inner": [
"ghost.4449aa4.png",
"ghost.4449aa4.png"
],
"home": {
"poster": "ghost.4449aa4.png"
}
}
這樣就完成了整個(gè)遠(yuǎn)程圖片資源加載器的配置,可以在new ImageLoader() 對(duì)象的 loading, loaded回調(diào)中看到圖片預(yù)加載的最終狀態(tài)status,數(shù)量totalcount,成功加載的圖片數(shù)量success,加載失敗的圖片數(shù)量fail, 加載圖片的總計(jì)耗時(shí)timecost(單位ms)。
創(chuàng)建ImageLoader對(duì)象時(shí)source字段的說(shuō)明:
new ImageLoader({
base: ImageSource.BASE,
source: [ImageSource],
loading: res => {
// 可以做進(jìn)度條動(dòng)畫
console.log(res);
},
loaded: res => {
// 可以加載完畢動(dòng)畫
console.log(res);
}
});
source字段接受一個(gè)Array類型的參數(shù),以上文中imageSource.js中的配置來(lái)說(shuō),寫了很多不同格式的數(shù)據(jù),使用
const ImageSource = require('./imageSource.js');
引入后,可以直接使用ImageSource來(lái)讀取各個(gè)部分的數(shù)據(jù),因此在配置source字段時(shí)可以直接把整個(gè)ImageSource對(duì)象放入進(jìn)去
source: [ImageSource]
也可以根據(jù)項(xiàng)目需要只加載其中一部分資源,如:
source: [ImageSource.imageList, ImageSource.single2]
這樣加載器在執(zhí)行時(shí)就會(huì)只載入source中寫入的部分,而不是整個(gè)ImageSource。
最后,在加載過(guò)程中如果過(guò)于耗時(shí),可以選擇在每個(gè)頁(yè)面的onLoad里單獨(dú)加載資源,做法類似于在app里調(diào)用,本文的示例是寫在app.js的onLaunch中。如果加載時(shí)間過(guò)長(zhǎng)可以做一個(gè)進(jìn)度條或者加載動(dòng)畫,優(yōu)化啟動(dòng)體驗(yàn)。預(yù)加載過(guò)的圖片會(huì)在微信內(nèi)存中緩存一到小程序進(jìn)程被關(guān)閉,因此在隨后的頁(yè)面里可以直接使用圖片。
const app = getApp();
const imgSource = require('../../imageSource.js');
Page({
data: {
base: imgSource.BASE,
src: imgSource.single1
},
onLoad: function () {
console.log(imgSource)
}
})
頁(yè)面上的Image會(huì)立即顯示,不需要重新發(fā)起加載圖片請(qǐng)求。個(gè)人研究結(jié)果,如有錯(cuò)誤、不足歡迎批評(píng)指正,相互探討。個(gè)人QQ: 837195936 熊
第二部分:如何開通一個(gè)小商店