前言
这篇文章开始我们就正式进入小程序的项目开发,这里主要功能包括:网络请求,轮播图,纵向列表,下拉刷新,上拉加载,item点击传值,页面跳转传值.
效果图
文件结构
配置
可以看到只有两个页面-index和info,所以在app.json中配置两个页面路径(注意该文件不能有注释)
{
"pages": [
"pages/index/index",
"pages/info/info"
],
"window": {
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"navigationBarBackgroundColor": "#000",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "white"
}
}
列表页面需要下拉刷新,所以在index.json中开启下拉刷新,在info中关闭下拉刷新,同时设置title
//index.json
{
"navigationBarTitleText": "小程序",
"enablePullDownRefresh": true
}
//info.josn
{
"navigationBarTitleText": "详情页",
"enablePullDownRefresh": false
}
页面
轮播图
轮播图由wx:for和<swiper-item>配合使用,wx:for="{{banners}}"
指定数据源数组,interval="1000"
指定自动切换的间隔,item为当前项的数据,index为下标,banners为js中的数据源,当js调用setdata并改变banners时,轮播图会刷新
<swiper class="swiper" indicator-dots="true" autoplay="true" interval="3000">
<block wx:for="{{banners}}">
<swiper-item>
<image src="{{item.url}}" class="slide-image" mode="aspectFill" bindtap="itemClick" id="{{index}}" />
</swiper-item>
</block>
</swiper>
- swiper组件提供一些属性,如自动切换,时间间隔,指示器等等
纵向列表
小程序不直接提供列表组件(如Android中的ListView,RecycleView),需要通过wx:for="{{listData}}
来重复渲染形成列表,原理同样也是绑定数组,数组更新时刷新列表
<view class="list">
<block wx:for="{{listData}}">
<view class="list-item">
<image src=" {{item.url}} " class="item-image" mode="aspectFill" bindtap="itemClick" id=" {{index}}"/>
<view class="item-text">
<text class="item-title ">{{item.type}}</text>
<view class="item-msg ">
<text class="item-title ">{{item.who}}</text>
<text class="item-title ">{{item.desc}}</text>
</view>
</view>
</view>
</block>
</view>
- 列表同样使用for来重复渲染,不同的是不需要
<swiper-item>
来包裹 - 可以使用
wx:key="_id"
来指定item的唯一性,如果不指定,微信会抛一个警告,但不会影响程序运行,具体wx:key的原理可查看官方文档 - 建议动态列表指定wx:key,这样效率会比较高,并且不会丢失item中的状态
数据
轮播图需要一个数组,列表需要一个数组,还需要记录当前页面,所以index的data部分:
Page({
data: {
banners: [],//轮播图数据源,
pageNum: 1,//当前页码
listData: []//列表数据
}
)}
这里使用gank.io的api拉取数据用于轮播图和列表,由于下拉和上拉都需要用到该请求,故提取为方法以便复用
,返回数据的格式:
{
"error": false,
"results": [
{
"_id": "587c6073421aa91194ca0e2c",
"createdAt": "2017-01-16T13:56:03.417Z",
"desc": "1-16",
"publishedAt": "2017-01-16T14:12:18.71Z",
"source": "chrome",
"type": "福利",
"url": "http://ww3.sinaimg.cn/large/610dc034gw1fbsfgssfrwj20u011h48y.jpg",
"used": true,
"who": "daimajia"
},
{
"_id": "5878471d421aa9119735ac13",
"createdAt": "2017-01-13T11:18:53.183Z",
"desc": "1-13",
"publishedAt": "2017-01-13T11:58:16.991Z",
"source": "chrome",
"type": "福利",
"url": "http://ww3.sinaimg.cn/large/610dc034gw1fbou2xsqpaj20u00u0q4h.jpg",
"used": true,
"who": "daimajia"
}
]
}
index.js数据处理
//获取应用实例
var app = getApp()
Page({
data: {
banners: [],//轮播图数据源,
pageNum: 1,//当前页码
listData: []//列表数据
},
requestData() {
var that = this
wx.request({
url: 'http://gank.io/api/data/福利/10/1',
success: function (res) {//更新数据刷新UI
banners: res.data.results,
listData: res.data.results
},
fail: function () {
},
complete: function () {
}
})
},
onLoad: function () {
this.requestData();
}
})
下拉刷新和底部自动加载
ok,经过上面的一些步骤,我的小程序已经可以顺利运行并展示动态数据了,但是列表一般会配套刷新和分页加载,在小程序中这两个操作同样也是有提供的:
-
onPullDownRefresh
为下拉的处理函数, -
wx.stopPullDownRefresh()
可以在请求完成后关闭拉下刷新, -
onReachBottom
为滑动到底部的处理函数,可用来做上拉加载分页
在index.json中配置开启了下拉刷新后,在index.js中处理对应事件:
Page({
onReachBottom: function () {//底部自动加载
this.data.pageNum++;
this.requestData();
},
onPullDownRefresh: function () {//下拉刷新
this.data.pageNum = 1;
this.requestData();
}
- 加载过程是耗时的,故需要给用户一些loading
- 另外现在轮播和列表使用的是同一个请求,但是轮播实际永远只需要展示第一页的数据(图片)就可以了,所以也需要做下数据处理,
- 网络请求出错应该给用户对应的提示
综合以上,则index.js(即逻辑层)最后的代码如下:
//index.js
//获取应用实例
var app = getApp()
Page({
onReachBottom: function () {
this.data.pageNum++;
this.requestData();
},
onPullDownRefresh: function () {
this.data.pageNum = 1;
this.requestData();
},
data: {
banners: [],//轮播图数据源,
pageNum: 1,//当前页码
listData: []//列表数据
},
requestData() {
var that = this
console.log("当前页码" + this.data.pageNum)
if (that.data.listData.length < 1) {//第一次进来展示加载框
wx.showToast({
title: '加载中',
icon: 'loading',
duration: 500
})
} else {
wx.showNavigationBarLoading()
}
wx.request({
url: 'http://gank.io/api/data/福利/10/' + this.data.pageNum,
success: function (res) {
console.log("请求成功" + res)
wx.stopPullDownRefresh()//停止下拉刷新动画
if (that.data.pageNum == 1) {
that.data.listData = []//清空数组
}
var list = that.data.listData;
for (var i = 0; i < res.data.results.length; i++) {
list.push(res.data.results[i]);
}
that.setData({
listData: list,//更新数据
banners: that.data.listData.slice(0,Math.min(9, that.data.listData.length))//截取数组
})
// success
},
fail: function () {
wx.showModal({
title: '加载出错',
showCancel: false
})
},
complete: function () {//加载完成
wx.hideToast()
wx.hideNavigationBarLoading()
}
})
},
onLoad: function () {
this.requestData();
}
})
- 轮播和列表数据分开使用两个数组存储,其中轮播为列表的第一页数据
- 由于
success
内部环境为wx.request
,故this相当于wx.request这个对象(js中,函数也是对象),对于Android开发者这一点是非常好理解的(相当于Android中的内部类),故需要在外面使用临时变量存储var that = this
,这样使用that则是指向page - 用到一些js的数据操作:
that.data.listData = []//清空数组
;list.push(res.data.results[i]);//数组添加数据
;that.data.listData.slice(0,Math.min(9, that.data.listData.length))//截取数组
;
点击跳转
点击轮播图或者列表中的item需要到对应的详情页,展示该项的详情信息,分为两个步骤:
列表点击传值
即处理itemClick,并且需要获取到该项的数据(banners[index]),所以在点击事件中需要附带当前的下标-index;
小程序提供两种事件中传值的方式:
1.使用组件通用属性传值,如id(适用于少量数据)
//wxml
<swiper class="swiper" indicator-dots="true" autoplay="true" interval="3000">
<block wx:for="{{banners}}">
<swiper-item>
<image src="{{item.url}}" class="slide-image" mode="aspectFill" bindtap="itemClick" id="{{index}}" />
</swiper-item>
</block>
</swiper>
//js
itemClick: function (event) {
console.log(event)
var index = event.target.id
},
2.使用事件中的dataset字段(适用于数据比较多)
//wxml
<swiper class="swiper" indicator-dots="true" autoplay="true" interval="3000">
<block wx:for="{{banners}}">
<swiper-item>
<image src="{{item.url}}" class="slide-image" mode="aspectFill" bindtap="itemClick" data-index="{{index}}" />
</swiper-item>
</block>
</swiper>
//js
itemClick: function (event) {
console.log(event)
var index = event.target.dataset.index
},
- dataset中的key使用data-keyName固定格式指定,并且大写会被转为小写,在取值的时候则使用转化后的驼峰命名形式的key(很奇葩,不得不吐槽一下)
跳转传值
ok,item的点击事件和下标处理完成,接下来就是跳转详情页了,那么小程序中跳转应该怎么附带参数呢,在详情页又该怎么取值呢?还是看代码:
itemClick: function (event) {
console.log(event)
var index = event.target.id//取事件中附带的index值
var item = this.data.listData[index]
wx.navigateTo({//跳转
url: '../info/info?title=' + item.desc + "&imageUrl=" + item.url + "&resType=" + item.type + "&source=" + item.who
})
},
首先,从动点击事件的参数中取到index,从而从数组中取到item数据,最后使用wx.navigateTo
跳转页面,该api需要指定跳转页面的路径,参数以key=value形式拼接在路径中(对于Android开发者是比较好理解的,这种形式与get请求参数拼接一致)
取值也非常简单,只需要在详情页的onLoad方法中取参数里的值即可,
//info.js
Page({
data: {
title: '',
imageUrl: '',
resType: '',
source: ''
},
onLoad: function (res) {//取值
wx.setNavigationBarTitle({//动态设置当行栏标题
title: res.title
})
this.setData({//取值并更新数据和UI
title: res.title,
imageUrl: res.imageUrl,
resType: res.resType,
source: res.source,
})
}
})
- 页面的参数传递全部需要key=value拼接的形式,在Android中是可以直接传递序列化对象的,但是小程序中好像并没有提供传递对象的方式;
- 并且所有的参数都必须是String类型,其他类型内部均会自动转为String传递,这一点也需要注意一下
ok,所有Demo中涉及到的内容基本都提到了,没有什么特别难的点,有些地方开发思路需要做一下转变,注意一下细节(小程序比较封闭,代码书写方式也很严格).下一篇会是进阶的内容,包括Tab页面,视频播放
才疏学浅,还请大家及时指出博客中的问题,不慎感激.源码github