注册登录

小程序远程图片资源按需预加载

2018-09-20
导读:最近做H5开发遇到个问题,为了防止页面打开时,出现大图加载缓慢的情况,写了一个图片资源管理器,今天顺便实现了一下小程序版。 特别说明一下,小程序由于资源包大小限制,很...

最近做H5开发遇到个问题,为了防止页面打开时,出现大图加载缓慢的情况,写了一个图片资源管理器,今天顺便实现了一下小程序版。

特别说明一下,小程序由于资源包大小限制,很多图片资源会存放到CND图片服务器上,为了实现小程序初始化时按需加载远程图片资源,实现了以下加载器,希望能解决部分小程序新人开发者预加载图片的苦恼。

特别强调:

本加载器为初级版本,暂未研究其他实现方式,当前实现方式需要在微信公众平台->设置->downloadFile合法域名,中添加想要加载的图片所在服务器合法域名。

原理介绍:

使用小程序自带API读取远程图片资源:

 

wx.getImageInfo({
 src: 'images/a.jpg',
 success: function (res) {
 console.log(res.width)
 console.log(res.height)
 }
}) 

 

这个接口可以创建图片组件对象并返回图片加载状态。

加载器用法:

1、在app.js的同级目录下创建一个ImageSource.js作为图片资源的路径管理文件(可以根据情况改为其他文件名称)。

2、在utils文件夹下放入ImageLoader.js或ImageLoader.min.js(附件)。

3、根据需要在对应的文件中创建ImageLoader对象(看下文)。

使用示例:

1、载入文件:

 

const ImageLoader = require('./utils/ImageLoader.min.js');
const ImageSource = require('./imageSource.js');

 

ImageLoader.min.js 为加载器源文件。

imageSource.js 为图片资源路径文件。

2、创建ImageLoader对象。

 

new ImageLoader({
 base: ImageSource.BASE,
 source: [ImageSource],
 loading: res => {
 // 可以做进度条动画
 console.log(res);
 },
 loaded: res => {
 // 可以加载完毕动画
 console.log(res);
 }
 });

 

参数

base : String 图片资源的基础路径 必填 示例: "https://image.example.com/static/images/"

source : Array 需要预加载的图片资源 必填 示例: [ImageSource.banners, ImageSource.imageList]

loading : function 图片加载中的回调方法 非必填 示例:

loaded : funciton 图片记载完成后的回调 非必填 示例:

加载器(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"
 }
 }
}

 

说明:

BASE 字段必填 根据自我需要填写。

其他图片资源支持:

1、直接key:value形式把图片路径写入,如:

 

"single1": "ghost.4449aa4.png" 

 

2、类似于pages目录把每个页面的远程资源写入到对应位置下,方便引用和管理,如:

 

"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、直接以数组方式把图片堆放在一个数组里,如:

 

"imageList": [
 "ghost.4449aa4.png",
 "ghost.4449aa4.png",
 "ghost.4449aa4.png",
 "ghost.4449aa4.png",
 "ghost.4449aa4.png"
 ] 

 

4、随意的资源数组,对象嵌套,如:

 

"folders": {
 "page1": "ghost.4449aa4.png",
 "page2": "ghost.4449aa4.png",
 "inner": [
 "ghost.4449aa4.png",
 "ghost.4449aa4.png"
 ],
 "home": {
 "poster": "ghost.4449aa4.png"
 }
 }

 

这样就完成了整个远程图片资源加载器的配置,可以在new ImageLoader() 对象的 loading, loaded回调中看到图片预加载的最终状态status,数量totalcount,成功加载的图片数量success,加载失败的图片数量fail, 加载图片的总计耗时timecost(单位ms)。

创建ImageLoader对象时source字段的说明:

 

new ImageLoader({
base: ImageSource.BASE,
source: [ImageSource],
loading: res => {
// 可以做进度条动画
console.log(res);
},
loaded: res => {
// 可以加载完毕动画
console.log(res);
}
});

 

source字段接受一个Array类型的参数,以上文中imageSource.js中的配置来说,写了很多不同格式的数据,使用

 

const ImageSource = require('./imageSource.js');

 

引入后,可以直接使用ImageSource来读取各个部分的数据,因此在配置source字段时可以直接把整个ImageSource对象放入进去

 

source: [ImageSource]

 

也可以根据项目需要只加载其中一部分资源,如:

 

source: [ImageSource.imageList, ImageSource.single2]

 

这样加载器在执行时就会只载入source中写入的部分,而不是整个ImageSource。

最后,在加载过程中如果过于耗时,可以选择在每个页面的onLoad里单独加载资源,做法类似于在app里调用,本文的示例是写在app.js的onLaunch中。如果加载时间过长可以做一个进度条或者加载动画,优化启动体验。预加载过的图片会在微信内存中缓存一到小程序进程被关闭,因此在随后的页面里可以直接使用图片。

 

const app = getApp();
const imgSource = require('../../imageSource.js');
Page({
 data: {
 base: imgSource.BASE,
 src: imgSource.single1
 },
 onLoad: function () {
 console.log(imgSource)
 }
})

 

页面上的Image会立即显示,不需要重新发起加载图片请求。个人研究结果,如有错误、不足欢迎批评指正,相互探讨。个人QQ: 837195936 熊

重磅推荐:小程序开店目录

第一部分:小商店是什么

第二部分:如何开通一个小商店

第三部分:如何登录小商店

第四部分:开店任务常见问题

第五部分:小商店可以卖什么

第六部分:HiShop小程序特色功能

第七部分:小程序直播

第八部分:小程序收货/物流

第九部分:小程序怎么结算

第十部分:小程序客服

第十一部分:电商创业

第十二部分:小程序游戏开发

电话咨询 微信咨询 预约演示 0元开店