第4章 莫凡商城首页的动态绑定设计
第4章莫凡商城首页的动态绑定设计
假设要开发一个天气预报小程序,可以使用函数来封装获取的天气数据,使用网络请求从天气API中获取实时数据,使用定义的模板渲染天
气信息,使用引用功能获得其他小程序提供的组件和功能。通过对这些功能的组合运用,可以打造一个功能强大、交互流畅的天气预报小
程序,为用户提供准确、即时的天气信息。
本章讲解莫凡商城首页的动态绑定设计,通过动态绑定设计可以实现页面动态交互效果。页面视图与逻辑层进行交互要用微信小程序函数
来处理。微信小程序提供了生命周期函数、页面事件函数、页面路由管理、自定义函数、setData()函数等函数,将逻辑层的数据渲染到页
面视图需要进行数据动态绑定,在页面视图中借助双大括号“{{}}”来取值。微信小程序可以通过网络请求获取数据、文件、会话等,以完成
动态交互。

4.1微信小程序函数处理
微信小程序的开发离不开各种函数,合理运用这些函数可以实现页面的生命周期管理、用户交互响应以及数据处理等功能。下面将重点介
绍几种重要的微信小程序函数及其应用场景。
4.1.1 生命周期函数
在使用Page()注册页面时,需要使用生命周期函数,包括页面加载时生命周期函数onLoad()、页面显示生命周期函数onShow()、页面初次
渲染完成生命周期函数onReady()、页面隐藏生命周期函数onHide()、页面卸载生命周期函数onUnload()和路由动画完成时生命周期函数
onRouteDone()。
示例代码如下:
Page({
onLoad: function (e) {
console.log("onLoad()页面加载时生命周期函数");
},
onShow: function () {
console.log("onShow()页面显示生命周期函数");
},
onReady: function () {
console.log("onReady()页面初次渲染完成生命周期函数");
},
onHide: function () {
console.log("onHide()页面隐藏生命周期函数");
},
onUnload: function () {
console.log("onUnload()页面卸载生命周期函数");
},
onRouteDone : function () {
console.log("onRouteDone()路由动画完成时生命周期函数");
},
})
页面第一次加载完成时,输出日志如图4.1所示。

图4.1 输出日志
4.1.2 页面事件函数
微信小程序页面事件函数包括监听用户下拉刷新事件处理函数 onPullDownRefresh()、监听用户上拉触底事件处理函数
onReachBottom()、监听用户滑动页面事件处理函数 onPageScroll (Object object)、监听页面尺寸发生改变的事件处理函数
onResize()、监听用户点击页面内“转发”按钮处理函数 onShareAppMessage(Object object)、分享到朋友圈事件处理函数
onShareTimeline()、收藏事件函数onAddToFavorites()、点击tab页面事件函数onTabItemTap()。
4.1.3 页面路由管理
微信小程序的页面路由都是由微信小程序框架来管理的,框架以栈的形式维护所有页面。栈作为一种数据结构,是一种只能在一端进行插
入和删除操作的特殊线性表,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后进入的数据在栈顶,需要读数据的时候从
栈顶开始读出数据(最后进入的数据被第一个读出来)。
微信小程序页面交互也是通过栈来完成的。微信小程序初始化时,新页面入栈;打开新页面时,新页面入栈;页面重定向时,当前页面出
栈,新页面入栈;页面返回时,页面不断出栈,直到返回指定页面,新页面入栈;tab切换时,页面全部出栈,只留下新的tabBar页面;重
加载时,页面全部出栈,只留下新的页面。
路由的触发方式及用到的页面生命周期函数如表4.1所示。
表4.1 路由的触发方式及用到的页面生命周期函数页面路由方式触发时机目标页面
生命周期函数源页面生命周期函数初始化打开小程序的第一个页面onLoad(),onShow()无打开新页面调用
API wx.navigateTo()或使用组件<navigator open-type="navigate"/>onLoad(),onShow()onHide()页面重定向调
用API wx.redirectTo()或使用组件<navigator open-type="redirect"/>onLoad(),onShow()onUnload()页面返回
调用API wx.navigateBack()或用户点击左上角的“返回”按钮onShow()onUnload()(多层页面返回时每个页面都会
按顺序触发onUnload())tab切换调用wx.switchTab()或用户切换TabonShow()(首次onLoad)onHide()重加载调
用API wx.reLaunch()或使用组件<navigator open-type="reLaunch"/>onLoad(),onShow()onUnload()

注意
wx.navigateTo()、wx.redirectTo()只能打开非tabBar页面;wx.switchTab()只能打开tabBar页面;wx.reLaunch()可以打开任意页面;页面底部的tabBar由页面决定,即只要是定义为tabBar
的页面,底部都有tabBar;调用页面路由的参数可以在目标页面的onLoad()中获取。
4.1.4 自定义函数
除了初始化数据和生命周期函数外,在Page()中还可以定义一些特殊的事件处理函数。在渲染层,可以在组件中加入事件绑定,当达到触
发条件时,就会执行Page()中定义的事件处理函数。事件处理函数的类型及触发条件如表4.2所示。
表4.2 事件处理函数的类型及触发条件函数类型触发条件bindtap当用户点击该组件的时候
会在该页面对应的Page()中找到相应的事件处理函数touchstart手指触摸动作开始touchmove手指触摸后移动
touchcancel手指触摸动作被打断,如来电提醒、弹窗touchend手指触摸动作结束tap手指触摸后马上离开
longpress手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发
longtap手指触摸后,超过350ms再离开,tap事件将不被触发(推荐使用longpress事件代替)
示例代码如下:
<view bindtap="clickMe" id="1" data-hi="WeChat">click me </view>
Page({
clickMe:function(e){
console.log(e);
console.log("type代表事件的类型:"+e.type);
console.log("timeStamp页面打开到触发事件所经过的毫秒数:" + e.timeStamp);
console.log("事件源组件的id:" + e.target.id);
console.log("事件源组件上由data-开头的自定义属性组成的集合:" + e.target.dataset.hi);
console.log("当前组件的id:" + e.currentTarget.id);
console.log("当前组件上由data-开头的自定义属性组成的集合:" + e.currentTarget.dataset.hi);
}
})
函数输出日志如图4.2所示。

图4.2 函数输出日志
4.1.5 setData()函数
Page.prototype.setData()为设值函数,用于将数据从逻辑层发送到视图层,同时改变对应的this.data的值。
setData()函数接收一个对象,以key、value的形式表示,将this.data中 key对应的值改变成value。
其中,key可以数据路径的形式给出,如array[2].message,并且不需要在this.data中预先定义。
示例代码如下:
<!--index.wxml-->
<view>{{text}}</view>
<button bindtap="changeText"> Change normal data </button>
<view>{{array[0].text}}</view>
<button bindtap="changeItemInArray"> Change Array data </button>
<view>{{object.text}}</view>
<button bindtap="changeItemInObject"> Change Object data </button>
<view>{{newField.text}}</view>
<button bindtap="addNewField"> Add new data </button>
//index.js
Page({
data: {
text: 'init data',
array: [{text: 'init data'}],
object: {
text: 'init data'
}
},
changeText: function() {
this.setData({
text: 'changed data'
})
},
changeItemInArray: function() {
this.setData({
'array[0].text':'changed data'
})
},
changeItemInObject: function(){
this.setData({
'object.text': 'changed data'
});
},
addNewField: function() {
this.setData({
'newField.text': 'new data'
})
}
})

注意
直接修改this.data是无效的,因为无法改变页面的状态,并且修改之后还会造成数据不一致。
单次设置的数据不能超过1024KB,需尽量避免一次设置过多的数据。
4.2微信小程序网络请求
微信小程序如果想动态地渲染页面,就需要从后台服务器接口获取数据,不能直接把数据写在页面或业务逻辑层里,因为这样的数据都是
静态数据。动态数据需要调用接口发起网络请求来获取,如想获取黑龙江省下辖地级市的数据,就可以通过网络请求API向省市区接口地址
发起请求,通过这个API获取数据,将它们渲染到页面视图上,从而达到动态显示的效果。
4.2.1 网络访问配置
微信小程序在发起网络请求前,需要在微信公众平台上进行访问域名的配置。小程序只允许访问已配置的域名,包括普通
HTTPS Hypertent Trarsfer Protocol Secure,超文本传输安全协议请求(使用wx.request())、上传文件(使用wx.uploadFile())、下载文件
(使用wx.downloadFile())和WebSocket通信(使用 wx.connectSocket())的域名。

注意
从基础库2.4.0版本开始,网络请求允许与局域网IP通信,但不允许与本机IP通信。从基础库 2.7.0版本开始,微信小程序提供了UDP(User Datagram Protocol,用户数据报协议)通信
(使用wx.createUDPSocket()),只允许与同个局域网内的非本机IP通信。
进入微信公众平台并登录,在小程序后台的“开发”→“开发管理”→“开发设置”→“服务器域名”中进行配置(需要用微信扫码确认身份),图
4.3和图4.4展示了配置流程和服务器域名配置。

图4.3 配置流程

图4.4 服务器域名配置
如果没有配置域名就直接访问,系统会提示错误信息,如图4.5所示。

图4.5 域名访问错误信息
出现这样的错误信息,有两种可能:一种是没有配置域名;另一种是配置了域名但没有生效,需要刷新项目配置后重新编译项目。
在配置时,应注意以下几点(下面的网址只是示例,不是真实网址)。
- 域名只支持HTTPS(wx.request()、wx.uploadFile()、
wx.downloadFile())和WSS(WebSocketSecure,WebSocket协议)
(wx.connectSocket())协议。
- 域名不能使用IP地址(小程序的局域网IP地址除外)或localhost。
- 可以配置端口,如https://myserver.com:8080,但配置后只能向
https://myserver.com:8080发起请求,如果向https://myserver.com、 https://myserver.com:9091等URL发送请求,则会失败。
- 如果不配置端口,如https://myserver.com,那么请求的URL中也不
能包含端口,即使是默认的443端口,如向https://myserver.com:443 发送请求也会失败。
- 域名必须经过ICP(Internet Content Provider,互联网内容提供商)
备案,不支持配置父域名、使用子域名。
- 出于安全考虑,api.weixin.qq.com不能被配置为服务器域名,相关
API也不能在小程序内调用。开发者应将AppSecret保存到后台服务器中,通过服务器getAccessToken接口获取access_token,并调用相关
API。
- 网络请求默认超时时间和最大超时时间都是60s,超时时间可以在
app.json文件或game.json文件中通过networktimeout配置。
下面详细讲解小程序的网络请求API及其用法。
4.2.2 请求数据API
wx.request()是用来请求服务器数据的API,它发起的是HTTPS请求,获取后台服务器接口的数据。wx.request()有一个Object对象参数,其
参数说明如表4.3所示。
表4.3 wx.request()的参数说明属性类型是否必填说明urlstring是开发者服务器接口地址
datastring/object/ArrayBuffer否请求的参数headerobject否设置请求的header。header中不能设置referer。
content-type默认为application/jsontimeoutnumber否超时时间,单位为ms。默认值为60000methodstring否默认
为GET。有效值有OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECTdataTypestring否默认为
JSON。如果设置了dataType为.json文件,则会尝试将返回的字符串用JSON.parse()解析;设置为其他值,则不对
返回的内容进行解析responseTypestring否响应的数据类型,text表示响应的数据为文本,arraybuffer表示响应的
数据为ArrayBuffersuccessfunction否接口调用成功返回的回调函数,res= {data: '开发者服务器返回的内
容'}failfunction否接口调用失败的回调函数completefunction否接口调用结束的回调函数(调用成功、失败都会执
行)
下面演示wx.request()的使用方法。
在JS文件的onLoad()函数里使用wx.request()请求服务器数据,示例代码如下:
Page({
onLoad:function(){
var requestTask = wx.request({
url:'https://api.mofun365.com:8888/api/address/getAddressList',
data:{
provinceId:'8'
},
method:'GET',
success:function (res) {
console.log(res);
},
fail:function(){
// fail
},
complete:function(){
// complete
}
});
}
})
服务器返回的数据如图4.6所示。

图4.6 服务器返回的数据
4.2.3 文件上传API
wx.uploadFile()可以将本地资源上传到服务器。客户端发起一个 HTTPS POST请求时,其中的content-type字段为multipart/form-data格
式。wx.uploadFile()的参数说明如表4.4所示。
表4.4 wx.uploadFile()的参数说明属性类型是否必填说明urlstring是开发者服务器
URLfilePathstring是要上传的文件资源的路径namestring是文件对应的key。开发者在服务器端通过key可以获取
对应的文件二进制内容headerobject否HTTP请求header。header中不能设置refererformDataobject否HTTP请求
中其他额外的form datatimeoutnumber超时时间,单位为mssuccessfunction否接口调用成功的回调函数
failfunction否接口调用失败的回调函数completefunction否接口调用结束的回调函数(调用成功、失败都会执
行)
下面演示调用wx.uploadFile()上传文件的方法,将选择的图片传到服务器里,示例代码如下:
Page({
onLoad:function(){
wx.chooseImage({
count:9, //最多可以选择的图片张数,默认为9
sizeType:['original','compressed'],//original为原图,compressed为压缩图,//默认二者都有
sourceType:['album','camera'],//album为从相册选图,camera为使用相机拍照,//默认二者都有
success:function(res){
var tempFilePaths=res.tempFilePaths;
const uploadTask=wx.uploadFile({
filePath:tempFilePaths[0],
name:'file',
header:{
'content-type':'Application/json'
},
formData:{
imgName:'我是图片名称',
imgSize:'122kb',
position:'wx' //自定义文件存放的文件夹
},
success:function (res) {
console.log(res);
}
});
}
})
}
})
输出日志如图4.7所示。

图4.7 输出日志
4.2.4 文件下载API
wx.uploadFile()是文件上传API,wx.downloadFile()是文件下载API,它们正好相反。wx.downloadFile()是客户端直接发起一个HTTPS GET请
求,从服务器中获得数据,返回文件的本地临时路径,单次下载允许的最大文件大小为50MB,并会下载到微信小程序客户端。
wx.downloadFile()的参数说明如表4.5所示。
表4.5 wx.downloadFile()的参数说明属性类型是否必填说明urlstring是开发者服务器
URLheaderobject否HTTP请求header。header中不能设置referertimeoutnumber否超时时间,单位为
msfilePathstring否指定文件下载后存储的路径(本地路径)successfunction否接口调用成功返回的回调函数,
res={data:'开发者服务器返回的内容'}failfunction否接口调用失败的回调函数completefunction否接口调用结束的
回调函数(调用成功、失败都会执行)
下面演示wx.downloadFile()的使用方法。从服务器中获取一张图片,然后将其下载到微信小程序客户端并显示出来。
(1)在WXML文件里,添加image图片组件来显示服务器传递过来的图片,示例代码如下:
<image src="{{src}}" style="width:270px;height:126px;"></image>
(2)在JS文件里,下载服务器中的一张图片,将它的临时路径赋给 src,示例代码如下:
Page({
data: {
src: ''
},
onLoad:function() {
var page=this;
const downloadTask=wx.downloadFile({
url: "https://api.mofun365.com:8888/images/banner/1555848473813.jpg",
type: 'image', //下载资源的类型,用于客户端识别处理,有效值:image/audio/video
success:function(res) {
console.log(res);
var tempPath=res.tempFilePaths;
page.setData({
src: tempPath
});
}
});
}
})
上传文件返回值如图4.8所示。

图4.8 上传文件返回值
4.2.5 项目实战:使用AI编程工具辅助实现动态获取
图书列和动态渲染页面效果1
.任务目标
实现图书列表显示功能的动态渲染,学会用微信小程序函数发起网络请求并将数据渲染到页面上。
2.任务实施
在3.4.3小节中,已完成静态页面布局设计,下面来实现动态获取图书列表和动态渲染页面效果。
打开通义灵码,输入以下内容并发送,如图4.9所示。
微信小程序,实现动态获取图书列表和动态渲染页面效果。IP地址从 app.js中的全局属性中获取,接口地址
为/api/goods/getHomeGoodsList,请求方式是GET,返回结果有3个数组,分别是“热门技术”列表、“特惠时刻”列表、“畅销图书”列表,怎么
实现?只需要给出JS部分。

图4.9 发送需求
3.AI生成
通义灵码根据需求生成了在小程序中实现动态获取图书列表和动态渲染页面效果的代码,如图4.10所示。
4.优化建议
在运行AI生成的代码后,发现其结果与我们的实际需求还有一定的差距,可以从以下两个方面进行优化。
- 把通义灵码中app.js中的IP地址换成自己的IP地址。
- 在生成的图书列表页面JS部分中找到获取接口数据的内容根据自己的
实际接口进行替换,并且根据实际接口返回的数据格式替换通义灵码返回的数据格式。

图4.10 通义灵码生成动态渲染图书列表和动态渲染页面的代码
5.页面展示
代码经过优化后,运行代码,页面样式如图4.11所示。

图4.11 动态渲染页面效果
4.3下拉刷新及窗口设置
页面下拉刷新是经常会用到的一个功能,有了这个功能,就可以通过刷新页面来获取更多的数据。微信小程序提供了开始下拉刷新、停止
下拉刷新及动态设置背景色等功能。要实现下拉刷新效果,就需要在小程序公共设置app. json文件里或者在各个页面的.json文件里配置
enablePullDownRefresh=true;需要提供两个事件处理函数,即用户下拉刷新事件处理函数onPullDownRefresh()、用户上拉触底事件处理函
数onReachBottom();还需提供两个API,即 wx.startPullDownRefresh()和wx.stopPullDownRefresh()。
4.3.1 下拉刷新API及事件处理函数1
.wx.startPullDownRefresh()
微信小程序使用wx.startPullDownRefresh()来进行刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。它有3个回调函数——成
功后回调函数、失败后回调函数、完成后回调函数,示例代码如下:
wx.startPullDownRefresh({
success:function(res){
//成功后回调函数
},
fail: function(res){
//失败后回调函数
},
complete:{
//完成后回调函数
}
})
2.wx.stopPullDownRefresh()
微信小程序使用wx.stopPullDownRefresh()来停止当前页面的下拉刷新。它也有3个回调函数——成功后回调函数、失败后回调函数、完成
后回调函数,示例代码如下:
Page({
onPullDownRefresh() {
wx.stopPullDownRefresh({
success: function(res){
//成功后回调函数
},
fail: function(res){
//失败后回调函数
},
complete: function(res) {
//完成后回调函数
}
})
}
})
下面介绍下拉刷新的完整实现方法。
(1)在demo.json文件里配置下拉刷新属性,具体代码如下:
{
"usingComponents": {},
"backgroundTextStyle":"dark", //dark表示显示刷新动画
"enablePullDownRefresh":true, //允许下拉刷新
"onReachBottomDistance":50//距离底部多远时触发刷新事件
}
(2)在demo.js文件里配置下拉刷新属性,具体代码如下:
Page({
onLoad: function (options) {
wx.startPullDownRefresh();//开始下拉刷新
},
/**
- 页面相关事件处理函数——监听用户下拉动作
*/
onPullDownRefresh: function () {
wx.stopPullDownRefresh()//得到结果后关掉刷新动画
},
/**
- 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
//触发上拉相关操作
},
})
下拉刷新效果如图4.12所示。

图4.12 下拉刷新效果
4.3.2 wx.setBackgroundColor()
微信小程序使用wx.setBackgroundColor()来动态设置窗口背景色,可以整体设置背景色,也可以单独设置顶部或底部背景色,该函数的参
数说明如表4.6所示。
表4.6 wx.setBackgroundColor()的参数说明属性类型是否必填说明
backgroundColorstring否窗口的背景色,必须为十六进制颜色值backgroundColorTopstring否顶部窗口的背景
色,必须为十六进制颜色值,仅iOS支持backgroundColorBottomstring否底部窗口的背景色,必须为十六进制颜
色值,仅iOS支持successfunction否接口调用成功的回调函数failfunction否接口调用失败的回调函数
completefunction否接口调用结束的回调函数(调用成功、失败都会执行)
示例代码如下:
Page({
onLoad: function (options) {
wx.setBackgroundColor({
backgroundColor: '#000000', // 窗口的背景色为深黑色
})
wx.setBackgroundColor({
backgroundColorTop: '#999999', // 顶部窗口的背景色为浅黑色
backgroundColorBottom: '#cccccc', // 底部窗口的背景色为灰色
})
wx.startPullDownRefresh();//开始下拉刷新
}
})
设置窗口背景色效果如图4.13所示。

图4.13 设置窗口背景色效果
4.3.3 wx.pageScrollTo()
使用wx.pageScrollTo()可以将页面滚动到目标位置,有两种滚动方式:
通过选择器的方式滚动和通过指定距离的方式滚动。通过这个API可以实现在长页面中回到顶部、回到底部的功能。wx.pageScrollTo()的参数
说明如表4.7所示。
表4.7 wx.pageScrollTo()的参数说明属性类型是否必填说明scrollTopnumber否滚动到页面的
目标位置,单位为pxdurationnumber否滚动动画的时长,单位为msselectorstring否选择器successfunction否接口
调用成功的回调函数failfunction否接口调用失败的回调函数completefunction否接口调用结束的回调函数(调用
成功、失败都会执行)
selector类似于CSS的选择器,但仅支持下列语法。
- ID选择器:#the-id。
- class选择器(可以连续指定多个):.a-class.another-class。
- 子元素选择器:.the-parent>.the-child。
- 后代选择器:.the-ancestor.the-descendant。
- 跨自定义组件的后代选择器:.the-ancestor>>>.the-descendant。
- 多选择器的并集:#a-node,.some-other-nodes。
示例代码如下:
wx.pageScrollTo({
scrollTop: 0,
duration: 300
})