微信小程序实现图片预加载组件


Posted in Javascript onJanuary 18, 2017

网页中的图片预加载

图片预加载对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验。我们知道在 Web 页面中实现图片的预加载其实很简单,通常的做法是在 JS 中使用 Image 对象即可,代码大致如下

var image = new Image()
image.onload = function() {
 console.log('图片加载完成')
}
image.src = 'http://misc.360buyimg.com/lib/img/e/logo-201305.png'

下面推荐几篇网页中实现图片预加载的文章:

     1、jquery 图片预加载 自动等比例缩放插件

     2、JS实现图片预加载无需等待

     3、jQuery简单实现图片预加载

然而在微信小程序(以下简称小程序)里要实现图片的预加载要更麻烦一些,因为小程序里并没有提供类似 Image 这样的 JS 对象。。

小程序必知必会

在进入正题前,需要了解以下小程序相关的知识(当然最好还是完整的学习一下官方文档):

  1. 小程序框架的核心是一个响应的数据绑定系统,整个系统分为视图层和逻辑层两块,视图层即页面模板(后缀为 .wxml 的文件),逻辑层即页面 JS 文件
  2. 小程序的页面模板由一系列的基础组件组合而成,如 view、text、button 等
  3. 页面内容的更新基于数据的单向绑定来进行,通过 JS 调用 Page 对象的 setData 方法来更新模板中绑定的数据
  4. 视图层到逻辑层的通信是通过事件完成的,在组件中声明事件的回调,JS 端可监听到界面交互的发生、组件状态的变化等
  5. 在 WXML 文件中,可通过 template 进行模板的复用,若 template 是在不同文件里定义的,需要先通过 import 语句进行引入

这里有个官方的简单例子可以用来帮助理解

<!-- 模板文件 foo.wxml -->
<view> Hello {{name}}! </view>
<button bindtap="changeName"> Click me! </button>
//脚本文件 foo.js
Page({
 data: {
 name: 'WeChat'
 },
 changeName: function(e) {
 this.setData({
 name: 'MINA'
 })
 }
})

运行这个页面会看到一行 Hello WeChat! 的文字及一个按钮,点击按钮后文字会变成 Hello MINA!

在小程序中加载图片

小程序提供一个 image 组件(类似于 HTML 中的 img 标签),可以设置 src 及加载成功或失败的回调,使用起来很简单

<!-- 模板文件 bar.wxml -->
<image src="http://misc.360buyimg.com/lib/img/e/logo-201305.png" bindload="imageOnLoad" binderror="imageOnLoadError" />
//脚本文件 bar.js
Page({
 imageOnLoad(ev) {
 console.log(`图片加载成功,width: ${ev.detail.width}; height: ${ev.detail.height}`)
 },
 imageOnLoadError() {
 console.log('图片加载失败')
 }
})

运行以上代码,顺利的话页面上会显示出一张图片,同时控制台会打印出带图片宽高的日志信息

将功能抽离成公用组件

接下来我们考虑实现这么一个功能,在页面上载入一张尺寸和 K 数都很大的图片,由于图片很大,下载需要一定的时间,而在这段时间内,用户看到的是空白或是不完整的图片,体验显然不好。

一种常用的优化手段是先加载一张缩略图,该缩略图通过样式设置为和原图一样的宽高,这样用户首先能很快速地看到一张模糊的图片,此时再去对原图做预加载,加载完成之后对缩略图进行替换,因为此时图片已经下载过了,所以界面上能无缝地切换为原图显示,效果如下:

微信小程序实现图片预加载组件

单张图片预加载

完成这个优化操作的关键就在于需要一个公共的图片预加载组件的支持,接下来我们分步骤来看看如何实现

  1. 新建 demo 页面及组件相关的文件 img-loader.js 和 img-loader.wxml,组件需要和页面一样有个模板文件,是因为小程序里无法动态地插入模板结构。然后在 demo.wxml 里通过 import 语句引用组件模板,在 demo.js 里通过 require 语句将组件脚本进行引入
  2. 在页面中通过 template 调用组件模板并传入数据,这里我们传递一个名为 imgLoadList 的图片数组过去
  3. 在页面脚本中的 onLoad 方法中对组件进行初始化,并将 this 对象传入,因为组件内必须通过 Page 对象的 setData 来更新模板里的内容
  4. 在组件的 img-loader.js 中定义一个 load 方法用来创建一个图片的加载,将传入的 src 添加到加载队列中,并使用 setData 方法更新队列数据
  5. 接下来在组件 img-loader.wxml 中通过接收到的图片队列数据,用 wx:for 指令去生成 image 组件来对图片进行加载,同时将成功及失败的回调绑定到 img-loader.js 中的方法中,最终再回调回 Page 对象中

微信小程序实现图片预加载组件

可以看出,由于小程序里无法动态地插入模板结构,所以相对于普通网页端的组件调用,这里多出了在 WXML 文件中引入及使用模板这个步骤,而其他部分对于调用方(即Demo 页面)来说则是相似的,下面是完整的 Demo 页面的代码

<!-- demo.wxml -->
<view class="img_wrap">
 <image wx:if="{{ imgUrl }}" src="{{ imgUrl }}" />
</view>
<button bindtap="loadImage">Click To Load Image</button>
<view class="msg">{{ msg }}</view>
<!-- 引入图片预加载组件 -->
<import src="../../img-loader/img-loader.wxml"/>
<template is="img-loader" data="{{ imgLoadList }}"></template>
// ------ demo.js ------
//引入图片预加载组件
const ImgLoader = require('../../img-loader/img-loader.js')
//缩略图 80x50 3KB
const imgUrlThumbnail = 'http://storage.360buyimg.com/mtd/home/lion1483683731203.jpg'
//原图 3200x2000 1.6MB
const imgUrlOriginal = 'http://storage.360buyimg.com/mtd/home/lion1483624894660.jpg'
Page({
 data: {
 msg: '',
 imgUrl: ''
 },
 onLoad() {
 //初始化图片预加载组件
 this.imgLoader = new ImgLoader(this)
 },
 loadImage() {
 //加载缩略图
 this.setData({
 msg: '大图正拼命加载..',
 imgUrl: imgUrlThumbnail
 })
 //同时对原图进行预加载,加载成功后再替换
 this.imgLoader.load(imgUrlOriginal, (err, data) => {
 console.log('图片加载完成', err, data.src)
 this.setData({ msg: '大图加载完成~' })
 if (!err)
 this.setData({ imgUrl: data.src })
 })
 }
})

如果把图片加载完成的回调统一指定成 Page 对象中的方法,则可以很方便地处理多张图片的加载,这里也写了个例子,效果如下:

微信小程序实现图片预加载组件

多张图片预加载

总的来说调用起来还算方便吧,img-loader 的组件代码略多这里就不贴出来啦,有兴趣的同学可以前往 Github 项目页面 查看,目前此组件已应用在京东购物小程序版中。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
jQuery textarea的长度进行验证
May 06 Javascript
基于Jquery的文字滚动跑马灯插件(一个页面多个滚动区)
Jul 26 Javascript
javascript页面动态显示时间变化示例代码
Dec 18 Javascript
jQuery 获取兄弟元素的几种不错方法
May 23 Javascript
jQuery焦点图轮播插件KinSlideshow用法分析
Jun 08 Javascript
JS FormData上传文件的设置方法
Jul 05 Javascript
基于js粘贴事件paste简单解析以及遇到的坑
Sep 07 Javascript
JS打印彩色菱形的实例代码
Aug 15 Javascript
在VUE中实现文件下载并判断状态的方法
Nov 08 Javascript
JavaScript canvas绘制渐变颜色的矩形
Feb 18 Javascript
微信小程序使用 vant Dialog组件的正确方式
Feb 21 Javascript
JS实现躲避粒子小游戏
Jun 18 Javascript
JavaScript原生节点操作小结
Jan 17 #Javascript
Javascript 两种刷新方法以及区别和适用范围
Jan 17 #Javascript
easyUI combobox实现联动效果
Jan 17 #Javascript
Angularjs实现搜索关键字高亮显示效果
Jan 17 #Javascript
React Router基础使用
Jan 17 #Javascript
JavaScript自定义分页样式
Jan 17 #Javascript
javascript实现页面滚屏效果
Jan 17 #Javascript
You might like
PHP如何通过传引用的思想实现无限分类(代码简单)
2015/10/13 PHP
Yii2框架制作RESTful风格的API快速入门教程
2016/11/08 PHP
PHP 匿名函数与注意事项详细介绍
2016/11/26 PHP
PHP从零开始打造自己的MVC框架之入口文件实现方法详解
2019/06/03 PHP
javascript new fun的执行过程
2010/08/05 Javascript
javascript hashtable 修正版 下载
2010/12/30 Javascript
jquery animate图片模向滑动示例代码
2011/01/26 Javascript
五个jQuery图片画廊插件 推荐
2011/05/12 Javascript
模拟用户点击弹出新页面不会被浏览器拦截
2014/04/08 Javascript
实例详解jQuery结合GridView控件的使用方法
2016/01/04 Javascript
js自调用匿名函数的三种写法(推荐)
2016/08/19 Javascript
webpack入门+react环境配置
2017/02/08 Javascript
JS中SetTimeout和SetInterval使用初探
2017/03/23 Javascript
JS实现两周内自动登录功能
2017/03/23 Javascript
深入理解ES6学习笔记之块级作用域绑定
2017/08/19 Javascript
Webpack框架核心概念(知识点整理)
2017/12/22 Javascript
iconfont的三种使用方式详解
2018/08/05 Javascript
了解JavaScript表单操作和表单域
2019/05/27 Javascript
mpvue实现微信小程序快递单号查询代码
2020/04/03 Javascript
js模拟实现百度搜索
2020/06/28 Javascript
python代码检查工具pylint 让你的python更规范
2012/09/05 Python
python实现随机梯度下降(SGD)
2020/03/24 Python
在IPython中执行Python程序文件的示例
2018/11/01 Python
pandas使用apply多列生成一列数据的实例
2018/11/28 Python
python正则爬取某段子网站前20页段子(request库)过程解析
2019/08/10 Python
Pyinstaller 打包exe教程及问题解决
2019/08/16 Python
在echarts中图例legend和坐标系grid实现左右布局实例
2020/05/16 Python
Python 开发工具通过 agent 代理使用的方法
2020/09/27 Python
JustFab加拿大:女鞋、靴子、手袋和服装在线
2018/05/18 全球购物
Java中会存在内存泄漏吗,请简单描述
2016/12/22 面试题
好人好事事迹材料
2014/02/12 职场文书
大学生个人求职信例文
2014/07/07 职场文书
应届本科毕业生求职信
2014/07/23 职场文书
竞聘自述材料
2014/08/25 职场文书
幼儿教师师德师风自我评价
2015/03/05 职场文书
小学生大队委竞选稿
2015/11/20 职场文书