前段时间完成了公司小程序的开发,一个做 iOS App 的人,做起小程序的感觉就是,JS 写原生 App 也可以这么流畅,原生开发者要丢饭碗啦!原先也研究过一段时间的 React Native,因为列表滚动太卡顿的性能限制,也就失去了研究的兴趣,现在看小程序,别有一番滋味。
也还是在前几天,Apple 封杀了 JSPatch。微博里流传的是这样一则笑话:“Apple: 听说 iOS 开发者没人要了?”。 不管历史的车轮怎么转,小程序很值得原生开发者学习下。
断断续续,写了好几篇小程序的文章,感觉自己写的东西都在微信开发者文档里,就一扔再扔。反复几次,终于有了这么一篇文章。不说基础,直接上 Demo:

从 4 个地方说起:
- 布局
- 模板
- 请求接口数据
- 页面传值
- 下拉刷新 上拉加载
- 分享
布局
采用 Flex 布局,对于 Flex 布局可以参考阮一峰老师的这两篇文章:
Flex 布局教程:语法篇
Flex 布局教程:实例篇
我们的页面每一行是长这个样子的(有时候会有图片 1 张或者多张,有时会没有):

页面结构代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <view class="postItem"> <view> <image class="userAvatar" src="{{ userAvatar }}"></image> </view> <view class="rightView"> <text class="userName">{{ user_nick_name }}</text> <text class="postTitle"> {{ title }} </text> <text class="postContent"> {{ subject }} </text> <view class="imagesBgView"> <view class="imageBgView" wx:key="property" wx:for="{{ imageList }}"> <image src="{{ item }}" class="postImage" catchtap='imageTapped' data-images="{{ imageList }}" data-current="{{ item }}" mode='aspectFill'/> </view> </view> <view class="postMoreInfoView"> <view> <text class="postTimeText">{{ last_reply_date }}</text> <text class="postTypeText">{{ board_name }}</text> </view> <view class="postViewCountCommentBgView"> <image src="http://iyiming-10052166.cos.myqcloud.com/eye.png" class="eyeImage"/> <text class="viewCountCommentCountText">{{ hits }}</text> <image src="http://iyiming-10052166.cos.myqcloud.com/comment.png" class="commentImage" /> <text class="viewCountCommentCountText">{{ replies }}</text> </view> </view> <view class="splitLineView" /> </view> </view>
|
页面样式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| .postItem { display: flex; flex-direction: row; } .userAvatar { width:80rpx; height:80rpx; margin-top: 20rpx; margin-left:20rpx; border-radius: 50%; background-color:#F3F3F3; } .userName { color: #78C51C; font-size:32rpx; } .rightView { display: flex; flex-direction: column; margin-top: 20rpx; margin-left: 10rpx; width: 100% } .postTitle { font-size: 32rpx; margin-right: 20rpx; margin-top: -20rpx; } .postContent { margin-top: -10rpx; font-size: 28rpx; margin-right: 20rpx; line-height: 38rpx; color: #393939 } .imagesBgView { display: flex; flex-wrap: wrap } .imageBgView { margin-right: 20rpx; margin-top: 10px } .postImage { width: 190rpx; height: 190rpx; background-color:#F3F3F3; } .postMoreInfoView { display: flex; justify-content: space-between; margin-top: 10rpx } .postTimeText { margin-top: 20rpx; font-size: 22rpx; color: #999999; } .postTypeText { margin-left:10rpx; margin-top: 20rpx; font-size: 22rpx; color: #999999; } .postViewCountCommentBgView { margin-right: 28rpx; } .eyeImage { width: 26rpx; height: 18rpx; } .viewCountCommentCountText { margin-top: 20rpx; margin-left: 10rpx; font-size: 22rpx; color: #999999; } .commentImage { width: 26rpx; height: 18rpx; margin-left: 10rpx; } .addPost { position: fixed; bottom: 30rpx; right: 30rpx; width: 90rpx; height: 90rpx }
|
模板
对于我们重复的每一行,微信提供了模板的功能,让我们更方便的重用代码,具体用法如下:
在 templates 文件夹里,添加一个文件夹 postItem 并创建文件:postItem.wxml。
1 2 3
| <template name="postItem"> ... </template>
|
在使用的地方,需要先引入再使用:
1 2 3
| <import src="../../templates/postItem/postItem.wxml" /> <template is="postItem" data="{{ ...postInfo }}" />
|
请求接口数据
微信提供了很方便的接口请求方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| wx.request({ url: 'https://URL', data: {}, method: 'GET', success: function(res){ }, fail: function() { }, complete: function() { } })
|
返回的数据都存在 res.data
里。
页面传值
从 A 页面传值到 B 页面,这个很简单:
1 2 3
| wx.navigateTo({ url: '../postDetail/postDetail?board_id=' + boardID + '&topic_id=' + topicID })
|
从 A 页面导航到 B 页面,B 页面点击按钮后,需要传值给 A 页面,可以在 B 页面将数据保存起来,再在 A 页面中获取。这样做显然不太好,有没有更好的办法?我这里使用了页面栈:
比如说页面 B 的某个 item 点击时,可以使用下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| itemTapped: function (e) { var item = e.currentTarget.dataset.info var pages = getCurrentPages(); var currPage = pages[pages.length - 1]; var prevPage = pages[pages.length - 2]; prevPage.setData({ plate: item }) console.log(prevPage.data) wx.navigateBack() }
|
在 gif 图这个例子里,我们有个预览图片的功能,点击某张图片进入图片预览,左右滑动,查看上一张下一张图片,先来看看微信给提供的预览图片的 API:
1 2 3 4 5 6 7 8 9 10 11 12 13
| wx.previewImage({ urls: [StringArray], success: function(res){ }, fail: function() { }, complete: function() { } })
|
点击图片时,我们需要传入当前点击的图片,还需要传入图片数组:
wxml 内容如下:
1
| <image src="{{ item }}" class="postImage" catchtap='imageTapped' data-images="{{ imageList }}" data-current="{{ item }}" mode='aspectFill'/>
|
js 内容如下:
1 2 3 4 5 6
| imageTapped: function (e) { wx.previewImage({ current: e.currentTarget.dataset.current, urls: e.currentTarget.dataset.images }); }
|
下拉刷新 上拉加载
对于下拉刷新、上拉加载,微信有直接给我们使用的 API:
1 2 3 4 5 6
| onPullDownRefresh: function () { }, onReachBottom: function () { }
|
一开始,我没有弄出这种上拉刷新效果,使用的 scroll-view
代替的,虽然能达到目的。体验不是很好走,了些弯路,还是换成了上面的这种方式,但是这里有一个小小的坑:
- 在要实现上拉刷新页面的 json 文件里,添加
"enablePullDownRefresh": true
- app.json 文件里
window
里要把 backgroundTextStyle
设置为 dark
。要不和默认的白色背景都是白色,看不出来是下拉刷新,这个就是上面所说的坑。
知道上面的两点,就能很好的实现下拉刷新。下拉加载顺其自然。
分享
要为某个页面实现分享功能,在页面的 js 文件里添加如下代码就可以了:
1 2 3 4 5 6 7 8
| Page({ onShareAppMessage: function () { return { title: '自定义分享标题', path: '/page/user?id=123' } } })
|
注意下路径,写对就好了。
另外微信阅读里有本《微信小程序入门指南》值得初学者看下,整体上讲的很细。小程序审核现在还很严格,要各种良民证。