最近要参加一个比赛,用小程序做了一个论坛,然后想在这里做一个总结,主要是整理下自己是如何一步步做出来的,有哪些经验值得以后学习中借鉴,有哪些值得反思和改正,然后也给将要使用云开发做小程序的人一点参考。
.
.
.
1、合理分配时间,不要一昧求快
我是负责后台的,说是后台,其实就是调用数据库,写js逻辑的。前前后后花了半个月左右做完,第一周主要是搞清楚小程序开发怎么做,第一天看了一个时长三小时左右的视频了解下整个流程和大概,分几次看的,便于消化,然后看了三天的开发文档(跟着开发文档写点小例子测试与熟悉),然后花了三天时间写项目。一周时间初版出来了,基本的功能都有。然后第二周主要是增加功能,和配合前端修改代码以及测试改bug。
,
,
,
视频资源:
28节课快速玩转微信小程序【黑马程序员】
建议1.25倍速,太快容易困。后面那个小项目可以简单看一遍,前面基础部分的可以跟着敲敲代码体验一下真机模式。
注意:这个视频没有涉及到后端,但是对理解小程序大概是怎么个回事还是挺有帮助的。
这里反思一下,在看视频的过程中,看到作者用插件写代码非常方便,然后自己上网下载试了几个都没达到作者的效果,最后弄了一个小时左右,也没弄出来,后来想了想,其实根本没必要,插件也好,小工具也好,这些都只是让人从繁杂的代码和重复的工作中解放,现在你还没达到每天需要敲巨量的代码,自己亲手敲敲还是可的。
.
.
.
开发文档:
这里说一下开发文档中哪些我觉得是要通读一遍的(有代码例子的,能上机验证的,最好自己都亲手敲一下,把一些最基本的先熟练(wxml、js),不然到时候开始写项目最基本的都要看文档就是没地基硬要盖高楼了:
.
.
.
先看指南部分,画圈的是最基础的,必须看的:
.
.
.
小程序开发指南写得很详细,仔细看
.
.
.
只负责后台的话,样式可以不看,但wxml一定要好好看
.
.
.
看到4.1基本就够用了,以后需要用到其他的功能的再来查就行,另外4.1我认为写得很好:
.
.
.
然后再看云开发部分,一开始看前两部分就可以了,记得动手验证!记得动手验证!记得动手验证!:
.
.
.
基本的就是以上这些了,当然后续开发过程中肯定不止用到这些东西,但是一开始的话够了,先吸收一点,等上手了一些,再来看其他的就很容易了。这里的组件和云开发是我后续查找得最多的地方,写得非常详细,基本需要的信息都能在这里找到:
.
.
.
微信小程序的开发文档真的写得非常详细了,而且难得是中文的,没有语言障碍,内容上通俗易懂,在后续开发的过程中一定要先在开发文档找找有没有你想要的信息,没找到再去百度后者谷歌,当然前提是你先得想好你的问题是什么,带着问题去找答案,才不会浪费时间。
.
.
.
上手项目:
写一个论坛,最基本的功能当然是发帖子、浏览帖子、收藏、搜索、评论。这里只贴关键的代码。
发帖:
//发布帖子
send_article: function () {
let that = this
wx.showLoading({
title: "发布中",
mask: true, //显示透明蒙层,防止触摸。为true提示的时候不可以对屏幕进行操作
})
//帖子信息上传到云端
wx.cloud.init()
const db = wx.cloud.database({
env: 'test'
})
db.collection("collection_1").add({
data: {
title: that.data.title,
content: that.data.content,
catlog: that.data.catlog,
imgFileIDArray: that.data.imgFileIDArray,
comments: [],
postTime_date: new Date(), //date型变量,方便传值给云函数,计算距今时间
postTime: new Date().toLocaleString(), //字符串型变量,时间显示更直观
calculatedTime: "", //距今时间,与用户打开帖子或者评论的当前时间有关
poster_NickName: that.data.poster_NickName,
poster_UserImgUrl: that.data.poster_UserImgUrl,
viewerNums: 1 //帖子浏览人数
},
success: function (res) {
//将生成的帖子的_id绑定到this.data里
that.setData({
_id: res._id
})
//更新发布的帖子数
db.collection("collection_2").where({
_openid: that.data._openid
}).update({
data: {
releaseID: db.command.addToSet(res._id),
releaseNums: db.command.inc(1) //原子自增1
},
success: function (res) {
//操作完毕
wx.hideLoading({})
//帖子发布完毕后导航到详情页面
wx.redirectTo({
url: '../../pages/page1/page1?_id=' + that.data._id + '&_openid=' + that.data._openid
})
},
fail: function (err) {
console.log(err)
}
})
},
fail: function (err) {
console.log(err)
}
})
},
.
.
.
浏览帖子:
*onLoad()进入页面进行加载,加载内容包括:
*1.加载帖子的信息(内容,发布人信息,图片,评论信息)
*2.更新每条评论的距今时间,calculatedTime
*3.获得我的信息(头像,微信名)
*
*/
onLoad: function (options) {
let that=this
wx.showLoading({
title:"加载中",
mask : true, //显示透明蒙层,防止触摸。为true提示的时候不可以对屏幕进行操作
})
that.setData({
_id:options._id, //接受上一个页面传递过来的参数_id、_openid
_openid:options._openid
})
console.log("_id:",that.data._id)
console.log("_openid",that.data._openid)
wx.cloud.init({
env:'test'
})
const db=wx.cloud.database()
//1.加载帖子的信息(内容,图片,距今时间,评论信息)
db.collection("collection_1").doc(that.data._id).get({
success:function(res){
that.setData({
//title:res.data.title,
content:res.data.content,
//catlog:res.data.catlog,
imgFileIDArray:res.data.imgFileIDArray,
comments:res.data.comments,
postTime:res.data.postTime,
postTime_date:res.data.postTime_date,
NickName:res.data.poster_NickName,
UserImgUrl:res.data.poster_UserImgUrl
})
//得到帖子距今的时间
wx.cloud.callFunction({ //更新帖子的距今时间calculatedTime
name:'cloudFunction_2',
data:{
postTime_date:that.data.postTime_date //传参为单个date型变量
},
success:function(res){
that.setData({
calculatedTime:res.result.calculatedTime,
my_openid:res.result.OPENID //调用云函数返回我的_openid
})
//2.获得我的信息(头像,微信名)
db.collection("collection_2").where({
_openid:that.data.my_openid
}).get({
success:function(res){
that.setData({
my_NickName:res.data[0].NickName,
my_UserImgUrl:res.data[0].UserImgUrl
})
//3.更新每条评论的距今时间,calculatedTime
if(that.data.comments.length!=0){ //贴子存在评论
wx.cloud.callFunction({ //更新comments对象数组中的comment_calculatedTime(评论的距今时间)
name:'cloudFunction_1',
data:{
comments:that.data.comments //传参为comments 对象数组
},
success:function(res){
that.setData({
comments:res.result.comments
})
//帖子照片、内容、评论已加载完毕
that.setData({
contentLoaded:true,
imagesLoaded:true,
commentLoaded:true
})
//加载完毕
wx.hideLoading({})
},
fail:function(err){
console.log(err)
}
})
}else{ //帖子不存在评论
//帖子照片、内容、评论已加载完毕
that.setData({
contentLoaded:true,
imagesLoaded:true,
commentLoaded:true
})
//加载完毕
wx.hideLoading({})
}
},
fail:function(err){
console.log(err)
}
})
}
})
},
fail:function(err){
console.log(err)
}
})
},
.
.
.
收藏帖子:
//收藏帖子
CollectPost:function(){
var app=getApp()
if(app.globalData.hasLogin==true){ //判断是否登录
let that=this
if(that.data.collectionStatus=="已收藏"){ //已收藏
console.log("帖子已收藏")
}else{
wx.cloud.init({
env:'test'
})
const db=wx.cloud.database()
db.collection("collection_2").where({
_openid:that.data.my_openid
}).update({
data:{
collectionsID:db.command.addToSet(that.data._id), //往数组字段中添加指定数据
collectionNums:db.command.inc(1) //原子自增1
},
success:function(res){
//改变button状态
that.setData({
collectionStatus:"已收藏",
collectionImgUrl:"../../images/shoucang_1.png" //已收藏的图标的本地路径
})
},
fail:function(err){
console.log(err)
}
})
}
}else{
console.log("请先登录!!")
}
},
.
.
.
搜索帖子:
//模糊查询
Search:function(){
wx.cloud.init({
env:'test'
})
let that=this
const db = wx.cloud.database() //初始化数据库
const _= db.command //db.command内含多种方法构建复杂的查询条件
db.collection("collection_1").where(_.or([//where中满足对象数组中的任意一个条件即成立
{
title:{
$regex:'.*'+ that.data.keyword,
$options: '1'
}
},
//模糊匹配title,content字段的内容,option=1表示不区分大小写
{
content:{
$regex:'.*'+ that.data.keyword,
$options: '1'
}
},
{ //对象数组指定字段的模糊查询条件写法
'comments.comment_content':{ //comments是评论的对象数组,comment_content是对象的一个字段
$regex:'.*'+ that.data.keyword, //只要comments中任意一个对象的comment_content包含keyword
$options: '1' //都将满足模糊查询的条件
}
}
])).get({
success:function(res){
//将对象数组转换为字符串,传送给page2页面
var model = JSON.stringify(res.data);
//跳转到搜索展示页面
wx.navigateTo({ //搜索跳转不存在二级页面,最后一个搜索页面的上一页面是第一个搜索页面之前的页面
url: '../../pages/page2/page2?model='+model
})
},
fail:function(err){
console.log(err)
}
})
},
.
.
.
评论:
// 发送评论
sendComment:function(){
var app=getApp()
if(app.globalData.hasLogin==true){ //判断是否登录
let that=this
let comments=that.data.comments
comments.reverse() //先将已有评论(按时间倒序存储)倒序,即先拨正方便压入新评论
comments.push({
comment_UserImgUrl:that.data.my_UserImgUrl,
comment_NickName:that.data.my_NickName,
comment_time_date:new Date(),
comment_time:new Date().toLocaleString(),
comment_calculatedTime:"刚刚" , //表示刚发布
comment_content:that.data.my_comment_content
})
comments.reverse() //在次将评论数组倒序,赋值给this.data.comments,进行列表渲染
that.setData({
comments:comments
})
//由于不能直接通过数据库改变他人穿创建的帖子的评论内容,
//只能通过云函数将新的评论数组comments更新如数据库,
//注意:comments里的对象是按照评论的时间倒序放置
wx.cloud.init({
env:'test'
})
wx.cloud.callFunction({
name:'cloudFunction_4',
data:{
comments:comments,
post_id:that.data._id
},
fail:function(err){
console.log(err)
}
})
}else{
console.log("请先登录!!")
}
},
.
.
.
2、学会总结问题、网上搜寻自己需要的答案
这里记录一下自己在写项目的过程中遇到的一些问题,并且是怎么一步步推理问题所在、总结问题、带着问题搜寻答案。
问题1:写的第一个页面就是发帖,其中最重要是用户上传照片到发帖页面、将图片存在云端、在帖子详情页面显示这些照片。
我的思路:
1.照片是不规则文档,自然不能存储在数据库中,肯定是存在存储中。
2.之前我在看云开发部分的文档时看到过关于上传文件的api:
这个临时文件路径我一开始的理解是用户要上传照片的绝对路径,我就试着上传一张照片,结果失败,于是我想,这个路径肯定不是绝对路径,既然是小程序的临时路径,是不是要上传的照片要放到小程序项目里,那么用户选择的照片的路径如何放在小程序里呢,这中间肯定有一个转换过程,我想弄清楚这个过程到底是什么,于是百度‘小程序云开发 上传照片’,很快找到了一篇我要的文章:
微信小程序云开发之图片上传wx.cloud.uploadFile()
看完之后明白了,其实转换过程就是调用wx.chooseImage()这个接口,然后去查了下官方文档:
得知小程序临时路径是调用wx.chooseImg()接口成功后,回调对象的一个参数。
接着去编译器验证了下,上传照片成功!上传照片之后,会返回照片在云端的ID,只要将这个ID存在数据库里,到时候就可以通过这个ID从存储中获取照片显示。
.
.
.
问题2:云开发如何进行模糊查询?
在web 项目中,模糊查询只需要写sql语句就可以了,用云开发来做小程序用的是json文档型数据库,自然不能通过sql语句。所以这个问题核心是 “云开发 模糊查询”,百度->筛选:
小程序云开发模糊查询
作者贴的解决方案只能进行一个字段的模糊查询,而我需要的是多字段,既然是多字段,联想到文档有讲where条件或 查询的写法,照着文档,最后成功解决!
.
.
.
问题3:如何在页面跳转中传递对象数组参数?
在输入关键字搜索到帖子之后,需要跳转到搜索结果展示页面,我的做法是先搜索得到对象数组,然后将对象数组传递到搜索结果页面进行显示(项目完成后想了下,其实传递搜索关键字要更好,在搜索展示页面来调取数据库,这样不会涉及到数组转换字符串,和字符串解密问题)。
这个问题涉及到两个方面,第一:小程序中下一个页面如何接受传过去的参数,在web项目里是通过request对象来接受的,小程序云开发是怎么做到的? 第二:对象数组可以直接传参和直接接收吗?所以问题核心是 “云开发 页面跳转 传递数组对象”
这个问题,我找了好几篇答案都不行,要么是没用到云开发,要么不是传对象数组,最后找了很久终于给我找到了:
微信小程序之页面跳转传递参数(对象,对象数组)
具体的解决方案都在这篇文章里,这里就不啰嗦了,写得非常好!↑↑↑↑
.
.
.
问题4:怎样显示帖子发表了多长时间,如“2分钟/小时/天 前”?
这个问题我是直接去百度的,因为我觉得这是完整的功能,网上肯定有实现方案(主要是确实不会…)。百度->筛选:
js实现文章或个人动态发布了多久的时间描述:几分钟前,几小时前,几天前等
看了这篇文章后,豁然开悟,其实实现思路很简单,定义一个云函数,传一个date型的实参(这个实参可以是帖子的发表时刻或者评论的发表时刻),然后new Date()得到当前的时刻,两个时间戳的差就是帖子发布了多长时间,只不过是以毫秒为单位的,在来个单位转换就够了。然后返回这个时间差。当然,项目中需要的可能不只是一篇帖子发表了多长时间,或者一个评论发表了多长时间,后面在计算首页推荐中多个帖子的发表时长和一个帖子多个评论的发表时长时,在一个个地调用云函数显然不现实,一个是很耗时间的,第二个涉及到云函数返回调用结果是异步的,可能没等第一次调用的云函数结果返回,for循环就结束了。所以自己在上面那篇文章编写的函数的基础上做了点修改,把传单个date型变量变成传整个评论数组或者帖子数组,只需调用一次云函数,在云函数里for循环得到每一个帖子的发表时长,再返回修改过的数组。这就要求我们在看别人文章的时候一定要理解,而不是简单的ctrl c、ctrl v,这样才能更好地用到自己的项目中去,也能真正地学到东西。
.
.
.
总结:学习小程序云开发,有问题一定要先查查官方文档,大多时候都能在里面找到解决思路,实在找不到了再来百度,但是前提是自己已经总结了问题,带着问题去找答案,这样才能快速找到自己需要的内容。然后,个人觉得,不停地去看类似“如何用小程序开发一个论坛” 这样的文章作用并不大,问题问得太大了…一开始可以了解下别人的思路,看个一篇左右这样的文章就可以了,多了也没必要,反正你是要自己写一个,又不是抄一个,何况在我看来去全部按着别人的思路来,去一点点调试别人的代码比自己写可要痛苦多了,并且那样只是重复造轮子,修修改改罢了,自认为是学不到什么东西的,再说了,自己写的代码也好维护多了。