微信小程序云开发一路走来所遇到的坑
在四月份初,和几位小伙伴一起开始了开发小程序的道路,时至五月初完成了小程序1.0.0版本。
这一路走来,真的是遇到很多坑,当然也学了不少知识。在开发的道路上,难免会遇到各种各样的问题。只有靠着顽强的毅力去一点一点解决它。其中在开发小程序的核心代码时,每天脑子都是快速运转。因为开发小程序不只是一个写代码的过程,这也是一个你去思考别人的想法的过程。
在这期间,你要想完成某一个功能的时候,你要想到用户的各种骚操作,然后你需要撸码撸出各种解决这些骚操作的骚代码!!!
这些骚操作可能使你脑子有点疲惫,但是当你完成了你的这个功能,你还是会感觉自己很不错!
接下来,我就聊一聊我的小程序之旅。
一、初识小程序云开发
小萌新们不要一听云开发这三个字感觉好高大上,是不是也很难呢?对比小程序的普通开发是不是要难很多。
答案:no !!! 小程序云开发才是小萌新门应该选择的开发模式,不需要你自己搭建服务器,不需要你来运维,不需要你自己管理数据库。这些后端功能都由云开发帮你实现,你需要做的就是写前端代码:包括页面和逻辑。
还好之前有做过网页的经验,学过html和css,所以小程序的页面布局问题不是很大。可第一次接触微信小程序,这逻辑该怎样写?数据怎么存?数据怎么拿出来?数据怎么渲染到界面?一系列问题出现在我脑海中。
经过两三天的研究,我终于对小程序的逻辑有了一点认知,能写出来个123。
我研究这几天研究的是啥呢?这就是开发小程序时所用到的宝典——微信官方文档!
废话,你开发小程序不看他的官方文档你看什么?
看小程序书本?我这个过来人可以负责任的跟你讲,看书本用处不大。
看官方文档比啥都靠谱,有问题还可以在官方社区进行提问。或者直接在官方社区搜索相关问题。
整个云开发小程序,首先看官方文档数据库的增删改查,这是最基础的。然后就是一些基础的API,官方给的API有示例代码,还有专门的说明,真的是“服务很到位”。
想要使用什么功能,一般性的会有相应的API,你可直接在官方文档里搜索功能名或者API。然后找到示例代码,复制粘贴——这是一名程序员多么成熟的招牌动作!
二、进入初级撸码阶段
初级撸码阶段,每写成功一个小小的功能就觉得很不错。都会有很大的成就感!这可能是初级阶段都会有的体验吧。
接下来我将分享整个小程序比较重要的知识点以及所遇到的坑。
你应该知道,在小程序中,用的比较多的就是官方给的API,就拿着这些API你才能将你的小程序做的生动起来,也容易很多。这里特别要注意的是,在使用API时,成功调用或者失败时,返回的形式要写成:
success:res=>{ } fail:res=>{ } complete:res=>{ }
这种形式是不会翻车的,当你成功调用API时,想从res参数获取数据就采用上面这种方式,而不要写成:
success(res){}
这种方式容易翻车,当res中有数据时,你想通过res获取数据,就容易有问题了。所以,建议:采用最上面那种方式!
openid
openID是微信用户所具有的唯一标识,所以在开发小程序的过程中,openID发挥着巨大的作用。例如身份识别。身份识别可操控着很多事项,比如访问权限、管理员等等。
想要获取openID也是一件非常简单的事情,当你新建一个云函数,期自动生成的代码返回结果中就包含有用户的openID。
const cloud = require(wx-server-sdk) cloud.init() exports.main = async (event, context) => { const wxContext = cloud.getWXContext() return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID, } }
在这个云函数中,返回结果有一项openid:wxContext.OPENID。
在调用这个js的文件的返回结果中接收到的就有用户的openID。
条件判断
在很多程序应用当中,系统会根据不同的用户身份展示不同的界面效果或者某一些特定的按钮、组件只会在某一些用户的操作下才会有。这就是需要通过判断条件来是否进行展示该组件。
<view wx:if="{{isMaster}}">组件内容</view>
像上面这个就会根据isMaster是否为true来判断是否展示该组件。当然isMaster是要在这个页面的js文件中通过一些条件进行判断赋值的,赋值的时候想要渲染出效果,就需要用到下面这种setData()方法。
this.setData({})
this.setData({})是非常重要并且必须用到的方法。举个例子,在一个页面中,从数据库获取了一个数据要展示在此页面中,想要展示内容,就必须是这个页面中的data{}里面的数据。这是就需要用到this.setData({})将从数据库获取到的这些值赋给本页面的data{}里面的数据,进而进行展示。如果不用this.setData({}),那么将不会动态的展示数据。所以想要直接将数据渲染出来,就需要用到此方法。
data:{ isMaster:false } this.setData({ isMaster:true })
循环
循环可以说是在每个程序中也必不可少的知识点。因为在一个应用程序中,免不了需要出现多个相同的页面,但是数据却不相同。这就是写完一个模板,数据从数据库中动态获取然后渲染到界面。
循环一般有两种方式:
<block wx:for="{{集合}}" wx:key="集合中的特有值"> <navigator url="path"> <view class="creatS"> </view> </navigator> </block>
上面这是第一种,for循环的是集合中的内容,一般是一个json格式的数据集。navigator 是用来跳转页面的,可以通过这个跳转到详情页。但是问题又来了,循环多个数据出来,如何判断点击的块跳转到的页面显示相对应的数据呢?因为在数据库中,每一条数据又有一个固定的id,云开发数据库固有的功能,所以,就是通过这个id进行判断的。但是写法该怎样写呢?往下看:
<navigator url="../path/path?id={{item._id}}"></navigator>
这样写就能跳转到特定页面了。
第二种也可以是除了block之外的view,就是说将for语句写在view里面,也是可以的,其他的跟上面的内容差不多。
通过this.setData({})无效
这个是令开发者很苦恼的一件事情,有时候我们想通过此方法将数据设置为这个页面data里面的数据,从而可以在这个页面的其他地方使用,结果却设置失败。这种情况呢,一般会出现在Promise 风格调用时不起作用,示例:
db.collection(todos).doc(todo-identifiant-aleatoire).get().then(res => { // res.data 包含该记录的数据 console.log(res.data) this.setData({ //无效 }) })
一般通过这种方式是无效的,所以想要使用获取到的数据该怎么办?答:直接在then里面写对应的逻辑代码,直接使用res.data。
那哪种情况下使用this.setData({})有效呢?下面这种:
db.collection(todos).doc(todo-identifiant-aleatoire).get({ success: function(res) { // res.data 包含该记录的数据 console.log(res.data) this.setData({ //有效 }) } }) 或者 db.collection(todos).where({ _openid: user-open-id, done: false }) .get({ success: function(res) { // res.data 是包含以上定义的两条记录的数组 console.log(res.data) this.setData({ //有效 }) } })
缓存
缓存用起来也挺方便,一般用在数据在不同页面的使用。比如我现在需要在A页面设置一个数据,然后在B页面去使用。这个时候就需要在A页面先设置缓存接着再去B页面获取缓存数据。
设置缓存:
wx.setStorageSync(key, dynamicValue)
其中key是改缓存的一个标识,你自己随意设置名字,稍后获取这个缓存的时候就是通过key值,dynamicValue一般是一个动态变量,也可以是固定值(需要加上单引号)
获取缓存:
var value = wx.getStorageSync(key)
这样你获取到的缓存值就存在了value当中
清除缓存:
wx.removeStorageSync(key)
清除缓存也是通过key值来识别。
页面数据传递
页面数据传递肯定是需要用到的,很多地方都少不了它。没有了它你的程序就像没了灵魂。
接下来,我就总结一下,页面之间数据的传递几种方式:
数据传递一般是伴随在页面的跳转过程中,在页面跳转的时候,我们可以通过路径进行传递数据:
第一种就是刚提到的navigator
<navigator url="../index/index?id={{item._id}}"></navigator>
这是传递了一个数据,我们也可以传递多个数据。例如:
<navigator url="../index/index?id={{item._id}}&school={{school}}"></navigator>
传递的这些数据,到index页面的onload()方法中添加一个参数options:
onload(options){
console.log(options)
}
传过来的数据就存放在options中。
第二种数据传递是,在js中跳转页面,将需要的值写在路径后面,示例:
wx.navigateTo({ url: ../index/index?pageid=+this.pageData, })
当然,这种也可以传递多个值,请看示例:
wx.navigateTo({ url: ../index/index?pageid=+this.pageData+&school=+this.data.school, })
比较简单,也最常用的传值方式就这两种了,仅供参考。
页面展示刷新
有时候可能需要不手动下拉刷新,而是只要界面显示出来,就要立马刷新。一般情况下,刷新获取数据都是在onload函数里面进行,但是如果我跳转到下一个页面更改了数据再返回回来,想要其自动更新,该怎么办呢?这时候就需要onShow()方法,该方法指的是页面显示执行该方法。如果你的本页面onload函数无参数,那么可以直接在onShow()方法里执行Onload方法即可:
onShow(){ this.onload() }
文本框填写数据进行提交
可能这个知识点也迷惑着大多初学者,趁此机会,我也阐述一下这个知识点吧。其实很简单,无论是输入框、文本域、单选钮、多选按钮等等一系列填值得地方,它都是放在form表单里面的,我们就通过form表单来获取的这些值:
wxml: <form catchsubmit="formSubmit" catchreset="formReset"> <input class="weui-input" name="input" placeholder="这是一个输入框" /> <button type="primary" formType="submit">Submit</button> <button formType="reset">Reset</button> </form> js: formSubmit(e) { console.log(form发生了submit事件,携带数据为:, e.detail.value) },
这样简单的完成之后,等你点击提交按钮,输入框中的值就存在参数e中了。接着存到数据库或者是怎样,就另写逻辑代码了。
当循环出某个集合后,如何在不跳转页面的情况下知道点击的是哪个数据
刚才我已经提到,在循环出某个集合后跳转详情页是通过id进行判断的,但是现在的需求是不要跳转页面,这该如何写呢?
也很简单,只需要在你循环的view中加上:
data-index="{{item._id}}"
加上这个属性,当你点击view时,就能动态的获取你点的那个view中的值。同样,也是在该view上加一个方法,在js中,该方法给个参数,这就OK了。
你想要获取的值就在这个参数中,具体位置在:
e.currentTarget.dataset.index
分享、邀请好友
小程序的分享功能是官方给出的API,开发者只需要调佣即可。接着我就讲一下按钮分享吧,因为小程序右上角分享没啥意思。
按钮分享那就是button啦,这时button写的时候是有讲究的哦:
<button bindtap="onShareAppMessage" open-type="share">分享</button>
切记:一定要写open-type="share"这个属性,这样,此按钮才能被小程序识别出是分享按钮。接着就是bindtap=“onShareAppMessage”,这个也不要改,就写onShareAppMessage,否则不起作用哦。
js: onShareAppMessage:function(){ return { title: 分享页面标题, imageUrl:分享出去别人所看到的小程序图片, path:这个是别人点击你分享的小程序,进来之后的页面, //切记!此路径要以path/开头,否则无效! success: function (res) { console.log("转发成功:"); }, fail: function (res) { console.log("转发失败:"); } } }
假如说你的一个页面有多个分享按钮,分别是不同的功能,请参考我的另外一篇文章:微信小程序之一个页面多个转发分享按钮,如何识别不同的按钮
数据库的使用
数据库的使用,在云开发的基础上真的是为开发者提供了很大的便捷。需要注意几个点:
在普通的js文件中,声明数据库对象时,要写下面这种形式:
const db = wx.cloud.database()
云函数,声明数据库对象,写下面这种方式:
const db = cloud.database()
发现两者的区别没?一个有wx一个没有。这是初学者容易入的坑,在此提醒一下。
数据库的权限
权限问题很重要,在使用数据库之前,首先看的就是权限,否则死都不知道是怎么死的。就比如,当你在查询数据的时候,查询条件根本没错,但就是返回不到结果,这时候90%的原因可能是你的数据库权限问题,没有访问数据的权限,虽然你可以将数据写进数据库,但是你拿不出来。所以,在使用之前,首要看的就是权限!!!
数据的增删改
只要牵涉到数据库中数据的增删改,你最好使用云函数,不会翻车。若是查询数据,可以不使用云函数,直接在js文件中查询即可。在数据的增删改中,有一些细节问题要注意:
db.collection(todos).add({ // data 字段表示需新增的 JSON 数据 data: { //data一定不能忘记 //所添加的字段 } }) .then(res => { console.log(res) })
这是新增一条数据,若是更改数据也是需要在update({})里面写上data:{},然后将要修改的字段再写进data里面。这也算是一个细节小坑,别被这些细节给打败了!
数据库删除数据
一般情况下,想要删除数据库中的数据,一般分为两种情况:
第一种,删除一整条数据,就是包含所有字段的一整条数据。
第二种,删除某一条数据中的某个字段,或者是某个字段数组中的某一个值。
这两种情况是两种不同的代码格式。
示例一:删除集合中的某一条数据。
db.collection(todos).doc(todo-identifiant-aleatoire).remove({ success: function(res) { console.log(res.data) } }) 或者 return await db.collection(todos).where({ //查询符合删除条件的语句 }).remove()
示例二:删除集合中某一条数据内字段数组内的某个值
db.collection(division) .where({ openID:wxContext.OPENID, _id:event._id }).update({ data:{ productionImage: _.pull({ url: _.eq(event.fileID) }) } })
像这种,就是通过筛选和否条件的某一条数据,然后更新数组字段,通过pull方法来删除符合条件的数据值。
注:在这里,需要注意的一点是在代码中有一个下划线 _ ,这个下划线也很容易被忽略掉,这其实是声明的一个对象。
const _ = db.command
使用云函数
在使用云函数时,也常常会有一些细节使你代码出现问题。我在此也提一下。
const cloud = require(wx-server-sdk) //必不可少的sdk cloud.init() //初始化云函数一定要写在初始化数据库对象前面 const db = cloud.database() const _ = db.command //需要用到此对象时,不要忘了声明 exports.main = async (event, context) => { const wxContext = cloud.getWXContext() return{ data:event } }
每当新增或者修改云函数中的代码之后,不要忘记点击上传,否则不生效!
大概就这些吧,能想到比较有用的就这些了,当然如果你有什么问题,可以留言给我,尽我所能帮助你!
整体来说,小程序的云开发还算是比较容易,就是坑太多,细节问题要注意,有啥问题,我能想到再补充进来!感谢你的阅读~