在两个月的微信小程序开发过程中,我曾走了不少弯路,也曾被很多现在看来十分可笑的问题所困扰。这些弯路与困扰,基本上都是由于当时对小程序的架构理解不够充分,对小程序的原理学习不够深入。我在解决这些问题的过程中,不仅学到了很多有意义的、对开发有直接帮助的知识点,更在微信小程序的架构与原理上补了不少课,对于我在微信小程序的设计上大有裨益。在这篇博客中,我将平常学习到的关于微信小程序的架构与原理的知识记录下来,同时记录我在一些功能上的代码实现,这些功能的实现曾经困扰过我、让我走了一些弯路。
微信小程序的推出,使得开发者的技术门槛降低、减少了推广与开发成本,也节约了用户的手机存储空间、节省了使用时间成本。它作为一种全新的连接用户与服务的方式,与传统意义上的应用程序有很多区别,同时在开发过程中也有一些共性。
小程序的前身是微信的JS API,最初这类API并不是对外暴露的,仅仅是提供给腾讯内部的一些业务使用。后来JS API进一步地引入了更多类别的接口,功能愈加丰富,包括拍摄、录音、语音识别以及二维码等重要功能,这些API整合成为一套完善的、公开的网页开发工具包,称为JS-SDK。JS-SDK在Web技术之上,做了很多方面的优化,使得Web开发者具有更多的能力。例如JS-SDK中的“微信Web资源离线存储”功能,该功能通过使用微信离线存储,使得Web开发者可以借助微信提供的存储能力,直接从微信本地加载Web资源,减少网页加载时间。
双线程机制
程序与页面
"window":{
"enablePullDownRefresh":true
}
之后在onPullDownRefresh()中添加监听到下拉动作所要执行的操作,比如在标题栏中显示加载3秒钟:
onPullDownRefresh(){
console.log('--------下拉刷新-------')
wx.showNavigationBarLoading() //在标题栏中显示加载
setTimeout(function () {
wx.hideNavigationBarLoading() //完成停止加载
wx.stopPullDownRefresh() //停止下拉刷新
}, 3000)
}
若要利用onReachBottom()函数实现上拉加载,可以在页面的json文件里设置:
"onReachBottomDistance":10,
表示距离底部还有多少px的距离时监听到上拉动作,当然也可以不设置,采用默认值0。之后在onReachBottom()函数中实现动作,以下是我实现的上拉加载更多表情的函数:
onReachBottom:function() {
var judge = 1
if (this.data.isLoading == 1) return;
//上拉加载方式:获取数据,拼接数组
var loadTime = this.data.globalShowIndex
console.log("loadTime:",loadTime)
//每次加载一行表情(3个)
var init = 9 + loadTime*3
var globalList = this.data.showListCache
console.log("globalLenth:",globalList.length)
if (init >= globalList.length) {
wx.showToast({
title: '抱歉,没有更多了',
duration:2000
})
}
else {
var temp3 = []
for (var i = init;i < init+3;i++) {
var path = globalList[i]
temp3.push({'file_id':path})
}
this.data.showPicList.push(temp3)
this.setData({
isLoading:0,
showPicList:this.data.showPicList
})
this.data.globalShowIndex++
}
}
此外,还可以wxml文件中做一些与上拉下拉动作相配合的设置,优化视觉体验,比如上拉加载时页面底部的提示:
<view wx:if='{{!isRefreshing}}' class="weui-loadmore">
<view wx:if='{{isLoading}}'>
<view class="weui-loading"></view>
<view class="weui-loadmore-tips">正在加载</view>
</view>
<view wx:elif='{{more}}'>
<!--bindtap为onReachBottom()回调函数,点击此处同样执行上拉加载动作-->
<view class="weui-loadmore-tips" bindtap='onReachBottom'>加载更多 </view>
</view>
<view wx:else>
<view class="weui-loadmore-tips">抱歉,没有更多了</view>
</view>
</view>
其中isRefreshing等指示变量需要在onReachBottom()函数中根据执行过程更改。
小程序的云开发
for (var i = 0;i < batchTimes;i++) {
var res = await db.collection("expression_visit_times").where({
id:fileid
}).skip(i*100).get()
if ((res.data[0] == null) && (i == batchTimes-1)) {
await db.collection('expression_visit_times').add({
data: {
id:fileid,
tag:filetag,
times:1
}
}).then(res=>{
console.log("第一次访问表情")
})
}
else if(res.data[0] != null){
visits = res.data[0].times
visits++
_id = res.data[0]._id
try{
await db.collection('expression_visit_times').doc(_id).
update({
data:{
times:visits
}
}).then(res=>{
console.log("更新成功")
})
}
catch(e){
console.log(e)
}
}
}
以上是我实现的对于expression_visit_times集合的一个比较复杂的操作:如果集合中存在file_id对应的表情的记录,那么就把它的访问次数加1;如果不存在,则新增一条该表情的访问记录。我将查询的结果保存下来进行判断,之后做进一步的操作。在我们的开发过程中,存在大量复杂的数据库操作,如果对于繁多的增删查改接口了解不够深入,可能会出现许多意想不到的问题。比如where().update()操作,在页面的逻辑函数中会报错,但是在云函数中可以执行。如果开发者不能在期限内非常熟练地掌握数据库操作,那么可以出于稳妥起见,可以将一些基础的、不容易出错的数据库操作进行嵌套、组合,保证正确性。
同步与异步
operation1({
success:function(res){
operation2({
success:function(res){
operation3({
success:function(res){
operaion4({
success:function(res){
operation5({})
}
})
}
})
}
})
}
})
看起来非常不舒服,维护起来也比较困难。就算我们能够忍受这种代码风格,那么还有一个致命的问题无从解决:for循环中的异步问题。如果一个异步操作被放在了for循环中,那它就会变成薛定谔的猫:你不知道它会在什么时候被执行,可能它的几次执行并不是严格按照for循环的遍历次序。
在云开发中,我们经常在云函数中使用Async-await方法,将异步请求变为同步请求。也就是说把让一个操作阻塞后面的操作,直到该操作完成。在云函数中使用Async-await比较简单,只需要以promise风格声明函数,之后加上async关键字,就可以在函数中使用await,将异步操作变成同步操作了:
exports.main = async (event, context) => {
const db = cloud.database()
const request = event.request
if (request == 1) {
//后续操作等待统计'expression_visit_times'集合记录数目
const countResult = await db.collection('expression_visit_times').count()
const total = countResult.total
// 计算需分几次取
var batchTimes = Math.ceil(total / 100)
if (batchTimes==0) {
batchTimes = 1
}
var resultArray = []
for (var i = 0;i < batchTimes;i++) {
var temp = await db.collection("expression_visit_times").skip(i*100).get()
resultArray = resultArray.concat(temp.data)
}
console.log("resultArray:",resultArray)
return {
data:resultArray
}
}
在小程序端,目前是不支持Async-await方法的。但是可以通过手动添加API的方式,进行小程序端的配置。参考链接如下:https://www.jb51.net/article/158648.htm.
手机扫一扫
移动阅读更方便
你可能感兴趣的文章