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


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 标题的自动翻转实现代码
Oct 14 Javascript
jquery中子元素和后代元素的区别示例介绍
Apr 02 Javascript
15款jQuery分布引导插件分享
Feb 04 Javascript
javascript数据结构之二叉搜索树实现方法
Nov 25 Javascript
基于原生JS实现图片裁剪
Aug 01 Javascript
Angular Module声明和获取重载实例代码
Sep 14 Javascript
js实现下拉框效果(select)
Mar 28 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
Oct 24 Javascript
在vue-cli中组件通信的方法
Dec 16 Javascript
vue封装一个简单的div框选时间的组件的方法
Jan 06 Javascript
浅谈vue限制文本框输入数字的正确姿势
Sep 02 Javascript
CountUp.js数字滚动插件使用方法详解
Oct 17 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中抽象类,接口功能、定义方法示例
2019/02/26 PHP
PHP添加PNG图片背景透明水印操作类定义与用法示例
2019/03/12 PHP
取得一定长度的内容,处理中文
2006/12/20 Javascript
用js+xml自动生成表格的东西
2006/12/21 Javascript
jq选项卡鼠标延迟的插件实例
2013/05/13 Javascript
js css 实现遮罩层覆盖其他页面元素附图
2014/09/22 Javascript
JavaScript组合拼接字符串的效率对比测试
2014/11/06 Javascript
JS+CSS实现淡入式焦点图片幻灯切换效果的方法
2015/02/26 Javascript
解决bootstrap中modal遇到Esc键无法关闭页面
2015/03/09 Javascript
JS基于VML技术实现的五角星礼花效果代码
2015/10/26 Javascript
JavaScript的String字符串对象常用操作总结
2016/05/26 Javascript
Vue.js系列之项目搭建(1)
2017/01/03 Javascript
vue slot 在子组件中显示父组件传递的模板
2018/03/02 Javascript
浅谈mvvm-simple双向绑定简单实现
2018/04/18 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
2018/09/19 Javascript
原生js实现随机点名功能
2019/11/05 Javascript
微信小程序向Java后台传输参数的方法实现
2020/12/10 Javascript
浅谈Python实现Apriori算法介绍
2017/12/20 Python
Python中循环引用(import)失败的解决方法
2018/04/22 Python
Python高级用法总结
2018/05/26 Python
PyQt5 QTable插入图片并动态更新的实例
2019/06/18 Python
python 字典 setdefault()和get()方法比较详解
2019/08/07 Python
Python实现Singleton模式的方式详解
2019/08/08 Python
Python中正反斜杠(‘/’和‘\’)的意义与用法
2019/08/12 Python
python实现滑雪者小游戏
2020/02/22 Python
Python模拟登录和登录跳转的参考示例
2020/10/30 Python
马来西亚最热门的在线时尚商店:FashionValet
2018/11/11 全球购物
澳大利亚婴儿、幼儿和儿童在线设计师商店:Smooch Baby
2019/02/16 全球购物
BannerBuzz加拿大:在线定制横幅印刷、广告和标志
2020/03/10 全球购物
比较基础的php面试题及答案-填空题
2014/04/26 面试题
如何写好优秀的创业计划书
2014/01/30 职场文书
《庐山的云雾》教学反思
2014/04/22 职场文书
日语系毕业求职信
2014/07/27 职场文书
银行贷款委托书范本
2014/10/11 职场文书
事业单位工作人员年度考核个人总结
2015/02/12 职场文书
2016年大学生暑期社会实践活动总结
2016/04/06 职场文书