最近做H5开发遇到个问题,为了防止页面打开时,出现大图加载缓慢的情况,写了一个图片资源管理器,今天顺便实现了一下小程序版。 特别说明一下,小程序由于资源包大小限制,很多图片资源会存放到CND图片服务器上,为了实现小程序初始化时按需加载远程图片资源,实现了以下加载器,希望能解决部分小程序新人开发者预加载图片的苦恼。 特别强调: 本加载器为初级版本,暂未研究其他实现方式,当前实现方式需要在微信公众平台->设置->downloadFile合法域名,中添加想要加载的图片所在服务器合法域名。 ![]() (文末有高清图) 原理介绍: 使用小程序自带API读取远程图片资源: [JavaScript] 纯文本查看 复制代码 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、载入文件: [JavaScript] 纯文本查看 复制代码 const ImageLoader = require('./utils/ImageLoader.min.js');const ImageSource = require('./imageSource.js'); ImageLoader.min.js 为加载器源文件。 imageSource.js 为图片资源路径文件。 2、创建ImageLoader对象。 [JavaScript] 纯文本查看 复制代码 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)源码: [JavaScript] 纯文本查看 复制代码 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)源码: [JavaScript] 纯文本查看 复制代码 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形式把图片路径写入,如:[JavaScript] 纯文本查看 复制代码 "single1": "ghost.4449aa4.png"2、类似于pages目录把每个页面的远程资源写入到对应位置下,方便引用和管理,如: [AppleScript] 纯文本查看 复制代码 "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、直接以数组方式把图片堆放在一个数组里,如: [JavaScript] 纯文本查看 复制代码 "imageList": [ "ghost.4449aa4.png", "ghost.4449aa4.png", "ghost.4449aa4.png", "ghost.4449aa4.png", "ghost.4449aa4.png" ] 4、随意的资源数组,对象嵌套,如: [JavaScript] 纯文本查看 复制代码 "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字段的说明: [JavaScript] 纯文本查看 复制代码 new ImageLoader({base: ImageSource.BASE,source: [ImageSource],loading: res => {// 可以做进度条动画console.log(res);},loaded: res => {// 可以加载完毕动画console.log(res);}}); source字段接受一个Array类型的参数,以上文中imageSource.js中的配置来说,写了很多不同格式的数据,使用[JavaScript] 纯文本查看 复制代码 const ImageSource = require('./imageSource.js');引入后,可以直接使用ImageSource来读取各个部分的数据,因此在配置source字段时可以直接把整个ImageSource对象放入进去 [JavaScript] 纯文本查看 复制代码 source: [ImageSource], 也可以根据项目需要只加载其中一部分资源,如:[JavaScript] 纯文本查看 复制代码 source: [ImageSource.imageList, ImageSource.single2]。这样加载器在执行时就会只载入source中写入的部分,而不是整个ImageSource。 最后,在加载过程中如果过于耗时,可以选择在每个页面的onLoad里单独加载资源,做法类似于在app里调用,本文的示例是写在app.js的onLaunch中。如果加载时间过长可以做一个进度条或者加载动画,优化启动体验。预加载过的图片会在微信内存中缓存一到小程序进程被关闭,因此在随后的页面里可以直接使用图片。 [JavaScript] 纯文本查看 复制代码 const app = getApp();const imgSource = require('../../imageSource.js');Page({ data: { base: imgSource.BASE, src: imgSource.single1 }, onLoad: function () { console.log(imgSource) }}) 页面上的Image会立即显示,不需要重新发起加载图片请求。 https://github.com/xiongchenf/imgLoader github上有最新源码及使用方法 个人研究结果,如有错误、不足欢迎批评指正,相互探讨。个人QQ: 837195936 熊 ![]() ![]() 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |