* 本文包含较多代码片段,PC端浏览推荐前往:
https://cloud.tencent.com/document/product/876/68589
文章目录
概述和开发准备
步骤1:编写登录功能及主页代码
步骤2:主页逻辑处理
步骤3:实现抽取纸条功能
步骤4:我的纸条页面设计
步骤5:我的纸条页面逻辑处理
步骤6:细节补充
概述
本文介绍如何用云开发相关能力,快速完成一个校园交友小程序的开发。并围绕抽个对象和我的纸条两个页面进行功能展示和讲解。
说明: 本实例教程所涉及到的相关源码材料,均已得到相应授权。
准备工作
前往微信开发者工具中开通云开发。
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/quick-start/miniprogram.html
操作流程
具体操作流程可分为以下6步。
- 1编写登录功能及主页代码
- 2主页逻辑处理
- 3实现抽取纸条功能
- 4我的纸条页面设计
- 5我的纸条页面逻辑处理
- 6细节补充
数据库表的设计
将用户的登录与用户对应放入的纸条数据分离开,就要建个 users_school 表来存储微信小程序用户,所有用户放入的纸条再建一个 body_girl_yun 表,为了便于让用户管理抽出的纸条就再建一个 body_girl_yun_put 表用来存储所有用户抽出的纸条。
打开微信开发者工具,单击云开发进入云开发控制台 > 数据库页面。单击新建按钮创建 users_school、body_girl_yun 和 body_girl_yun_put 三个集合,如下图所示:
步骤1:编写登录功能及主页代码
操作步骤
小程序配置及页面创建
1、app.json 中,配置两个页面的路径:
代码语言:javascript复制"pages": [ "pages/index/index", "pages/history/history" ]
配置好后刷新开发者工具,就会在页面 pages 文件夹下生成 index,history 文件夹以及对应的 .js
,.wxml
, .wxss
和 .json
文件。
2、在 app.json 中设置 tabbar 的位置,在页面顶部以及设置里面的内容:
代码语言:javascript复制"tabBar": { "color": "black", "selectedColor": "#D00000", "position": "top", "list": [{ "pagePath": "pages/index/index", "text": "抽个对象" }, { "pagePath": "pages/history/history", "text": "我的纸条" } ] },
3、在 app.js 里新增全局的数据,用来存放当前用户的 openId:
代码语言:javascript复制this.globalData = { openId: '' }
实现用户登录功能及 openId 的记录
1、右击当前环境文件夹,单击新建 Node.js 云函数,并将文件命名为 login_yun。
2、进入 login_yun 目录下的 index.js 文件,在 cloud.init()
函数内配置环境。
cloud.init( { // env 参数说明: // env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源 // 此处请填入环境 ID, 环境 ID 可打开云控制台查看 // 如不填则使用默认环境(第一个创建的环境) // env: 'my-env-id', env: 'cloud1234567890XXXXXXX' })
3、在云函数入口函数里进行 openId 的操作
代码语言:javascript复制exports.main = async (event, context) => { const wxContext = cloud.getWXContext()
const openId = md5(wxContext.OPENID)
// 查询这个openid下有无数据 let user_data = await db.collection("users_school").where({ openId: openId }).get()
// 没有此用户则将openId添加到数据库 if(user_data.data.length === 0){ try{ let data_add = await db.collection("users_school").add({ data: { openId: openId } }) return { data_add, openId, status: 202 // 新添加的数据 } } catch(e){ console.error(e) } // 有了则直接返回 }else{ return { user_data, status: 200 // 已经有了用户 } }}
4、然后右击 login_yun 文件夹,单击上传并部署:云端安装依赖,即完成了云函数的编写。
5、登录功能的云函数的调用,是在 index 页面加载 index.js 时进行调用,且在 onload 的生命周期中。
代码语言:javascript复制const that = this if (wx.getUserProfile) { that.setData({ canIUseGetUserProfile: false, }) } wx.cloud.callFunction({ name: 'login_yun' // 调用云函数 }).then(res => { console.log(res) if(res.result.status === 200){ // 存到全局的globalData里,便于后续使用 app.globalData.openId = res.result.user_data.data[0].openId }else{ app.globalData.openId = res.result.openId } })
编写 index 前端页面
1、顶部的轮播图,直接可以用小程序提供的 swiper 加上 swiper-item 标签来实现。
代码语言:javascript复制<view class="swiper_view"> <swiper autoplay="true" interval="3000" duration="500" circular="true" class="swiper"> <swiper-item> <image mode="widthFix" src="../../images/_2.jpg"></image> </swiper-item> <swiper-item> <image mode="widthFix" src="../../images/_1.png"></image> </swiper-item> </swiper> <!-- scaleToFill --></view>
2、中间的盒子部分用基本的标签、图片和 CSS 样式来编写。单击放入与抽取都会跳出一个收集信息的框,使用 bindtap 来绑定点击的事件,并在 index.js 里处理对应的事件。
代码语言:javascript复制<view class="body_bottom"> <view class="body_bottom_put" bindtap="putBody">放入一张男生纸条</view> <view class="body_bottom_out" bindtap="outBody">抽取一张男生纸条</view></view>
3、黑遮罩层用一个 view 标签,结合 CSS 的样式来完成。点击遮罩层对应 cancelHide 来隐藏遮罩层。
代码语言:javascript复制<view class="hide" wx:if="{{putBodyMask || outBodyMask || putGirlMask || outGirlMask || xuzhiMask || xieyiMask}}" bindtap="cancelHide"></view>
CSS 占满整个屏幕,加上颜色与透明度即可。
代码语言:javascript复制/* 遮罩层 */.hide { width: 100vw; height: 100vh; background-color: black; opacity: 0.5; position: fixed; top: 0vw; left: 0vh;}
4、男女生放入与抽取的弹出框,picker 用来选择分类的不同的学校。
代码语言:javascript复制<picker bindchange="bindSchoolChangePut" value="{{indexBody4}}" range="{{arrayBody4}}" class="out_body_content_2_picker"> <view> - {{arrayBody4[indexBody4]}} - </view></picker>
5、将 index 前端页面和样式细化后,最后效果如下图所示:
步骤2:主页逻辑处理
操作步骤
1、进入 index.js 页面,在 onload 的生命周期里,调用 login_yun 云函数实现登录的操作
代码语言:javascript复制wx.cloud.callFunction({ name: 'login_yun' }).then(res => { console.log(res) if(res.result.status === 200){ app.globalData.openId = res.result.user_data.data[0].openId }else{ app.globalData.openId = res.result.openId } })
2、在 index.js 页面,添加 data 存放所需要的数据。
代码语言:javascript复制data: { // 遮罩层标志 putBodyMask: false, putGirlMask: false, xuzhiMask: true, // 抽出的遮罩层 outBodyMask: false, outGirlMask: false, // 交友宣言 textareaBody: '', textareaGirl: '', // qq微信号 numberBody: '', numberGirl: '', // 上传图片预览的src srcListBody: [], srcListGirl: [],
// 放入的学校 arrayBody4: ["河南理工大学", "焦作大学", "焦作师范"], indexBody4: 0, // 纸条的生命 arrayBody2: ["被抽中一次销毁", "被抽中两次销毁", "被抽中三次销毁"], indexBody2: 0, arrayBody3: ["河南理工大学", "焦作大学", "焦作师范"], indexBody3: 0,
// 放入的学校 arrayGirl4: ["河南理工大学", "焦作大学", "焦作师范"], indexGirl4: 0 // 纸条的生命 arrayGirl2: ["被抽中一次销毁", "被抽中两次销毁", "被抽中三次销毁"], indexGirl2: 0, arrayGirl3: ["河南理工大学", "焦作大学", "焦作师范"], indexGirl3: 0, // 添加图片的加号 addMask: true },
3、学校选择的逻辑。
- picker 中 bindchange="bindSchoolChangePut",通过 bindSchoolChangePut 来触发学校改变的事件,选择对应的学校。
- e.detail.value 来获取在 data 中绑定的学校的列表索引。
// 放入时,学校的选择 bindSchoolChangePut: function(e){ this.setData({ indexBody4: parseInt(e.detail.value) }) }
4、在点击确认放入,触发对应的surePutBodyBtns事件,再进行判断,进而实现限制交友宣言长度。
代码语言:javascript复制if(that.data.textareaBody.length < 20){ return wx.showToast({ title: '交友宣言太短', icon: 'error', duration: 2000 }) }
5、上传微信号的正则匹配。
代码语言:javascript复制if(!(/^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})) d{8})$/).test(that.data.numberBody) && !(/^[a-zA-Z]([-_a-zA-Z0-9]{6,20})$/).test(that.data.numberBody)){ return wx.showToast({ title: '微信号格式错误', icon: 'error', duration: 2000 }) }
微信官方定义的微信号规则:
- 可使用6-20个字母、数字、下划线和减号。
- 必须以字母开头(字母不区分大小写)。
- 不支持设置中文。
6、实现本地图片的选择,一次上传限制一张,并且进行图片大小的限制,cloudPath 随机配置存储在云存储里的路径。
代码语言:javascript复制// 选择本地图片 chooseImgGirl: function(){ const that = this wx.chooseImage({ count: 5, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success (res) { // tempFilePath可以作为img标签的src属性显示图片 if(res.tempFiles[0].size > 1200000){ return wx.showToast({ title: '图片过大', icon: 'error', duration: 2000 }) }
const filePath = res.tempFilePaths[0] let timeStamp = Date.parse(new Date()); const cloudPath = "image/" timeStamp filePath.match(/.[^.] ?$/)[0] that.pageData.filePath = filePath that.pageData.cloudPath = cloudPath that.setData({ srcListGirl: res.tempFilePaths }) } })
7、单击纸条的生命,相应值的选择对应数据库 life 字段。
8、点击确认放入之后,相应逻辑是先上传图片,再上传 location,weChatId 等信息到 body_girl_yun 表,上传成功要跳转到 history 页面。
代码语言:javascript复制// 上传图片的api,先上传图片到云存储wx.cloud.uploadFile({ cloudPath, filePath, success: function(res){ wx.hideLoading() wx.showLoading({ title: '信息上传中', mask: true }) // 上传图片完成后上传数据 db.collection("body_girl_yun").add({ data: { location: that.data.indexGirl4, weChatId: that.data.numberGirl, picture: res.fileID, life: parseInt(that.data.indexGirl2) 1, des: that.data.textareaGirl, sex: 2, openId: app.globalData.openId, time: new Date().getTime() } }).then(result => { wx.hideLoading()
that.pageData = { filePath: '', cloudPath: '' } that.setData({ putGirlMask: false, srcListGirl: [], textareaGirl: '', numberGirl: '' }) // 上传完成后跳转到history页 wx.switchTab({ url: '/pages/history/history', success: res=>{ wx.showToast({ title: '放入纸条成功', icon: 'success' }) }, fail: err => { wx.showToast({ title: err, icon: 'error' }) } }) } })
9、页面底部两个点击事件:联系客服与uu须知。联系客服主要是在 index.wxml 里通过小程序的 open-type=“concat” 来实现。
index.html
代码语言:javascript复制<!-- 底部的通知 --><view class="bottom_view"> <button bindtap="xuzhi">UU须知</button> <!-- <text class="heng">|</text> --> <button bindcontact="contact" open-type="contact">遇到问题?联系客服</button></view>
index.js
代码语言:javascript复制// 点击UU须知 xuzhi: function(){ this.setData({ xuzhiMask: true }) }, // 联系客服 contact: function(){ console.log() }
步骤3:实现抽取纸条功能
操作步骤
1、随机抽取可以用微信开放文档提供的 开发者资源 来查找,进行随机的查询抽取,抽取的条件是“性别,学校和生命值必须大于0”。
代码语言:javascript复制// 随机抽取 db.collection('body_girl_yun').aggregate().match({ sex: 1, location: parseInt(that.data.indexBody3), life: _.gt(0) // 生命值要大于0 }).sample({ size: 1}).end()
2、抽到则处理,抽不到则提示处理时要把生命值减1。
代码语言:javascript复制// 数据库没有这个学校的男生的纸条就 if(res.list.length == 0){ return wx.showToast({ title: '此学校暂无纸条', icon: 'error', mask: true }) }// 抽取到了纸条,则进行操作 // 生命值减一, 生命值为0的不会抽出来 db.collection('body_girl_yun').where({ _id: res.list[0]._id }).update({ data: { life: parseInt(res.list[0].life) - 1 } }).then( resultUpdate => { wx.showToast({ title: '抽取成功', icon: 'success', mask: true }) }).catch(err=>{ wx.showToast({ title: err, icon: 'error' }) })
3、把数据写到 body_girl_yun_put 表中。
代码语言:javascript复制// 并将数据添加到 body_girl_yun_put db.collection('body_girl_yun_put').add({ data: { picture: res.list[0].picture, des: res.list[0].des, location: res.list[0].location, sex: res.list[0].sex, weChatId: res.list[0].weChatId, openId: app.globalData.openId, time: new Date().getTime() } }).then( resultAdd => {
}).catch(err=>{ wx.showToast({ title: err, icon: 'error' }) }) })
4、数据存入成功则跳转页面 history。
代码语言:javascript复制wx.switchTab({ url: '/pages/history/history', success: res=>{ wx.showToast({ title: '抽出纸条成功', icon: 'success' }) }, fail: err => {
} }) that.setData({ outBodyMask: false })
5、加上提示框与 loading 效果,wx.showLoading, wx.hideLoading(), 并添加了一些基本的错误处理。
代码语言:javascript复制// 确认抽取一张男生纸条 sureOutBodyBtn: function(){ const that = this wx.showLoading({ title: '随机抽取中', mask: true }) // 随机抽取 db.collection('body_girl_yun').aggregate().match({ sex: 1, location: parseInt(that.data.indexBody3), life: _.gt(0) // 生命值要大于0 }).sample({ size: 1}).end() .then(res => { wx.hideLoading() // 数据库没有这个学校的男生的纸条就 if(res.list.length == 0){ return wx.showToast({ title: '此学校暂无纸条', icon: 'error', mask: true }) }
console.log(res) // 生命值减一, 生命值为0的不会抽出来 db.collection('body_girl_yun').where({ _id: res.list[0]._id }).update({ data: { life: parseInt(res.list[0].life) - 1 } }).then( resultUpdate => { wx.showToast({ title: '抽取成功', icon: 'success', mask: true }) }).catch(err=>{ wx.showToast({ title: err, icon: 'error' }) })
// 并将数据添加到 body_girl_yun_put db.collection('body_girl_yun_put').add({ data: { picture: res.list[0].picture, des: res.list[0].des, location: res.list[0].location, sex: res.list[0].sex, weChatId: res.list[0].weChatId, openId: app.globalData.openId, time: new Date().getTime() } }).then( resultAdd => {
wx.switchTab({ url: '/pages/history/history', success: res=>{ wx.showToast({ title: '抽出纸条成功', icon: 'success' }) }, fail: err => { wx.showToast({ title: err, icon: 'error' }) } })
// console.log("数据add"resultAdd) that.setData({ outBodyMask: false }) }).catch(err=>{ wx.showToast({ title: err, icon: 'error' }) }) }) }
步骤4:我的纸条页面设计
我放入的纸条页面设计
1、顶部的“我放入的纸条”与“我抽到的纸条”通过改变 active 的值来切换 class。
代码语言:javascript复制<view class="top_title"> <text class="{{active === true ? 'on': ''}}" bindtap="inBtn">我放入的纸条</text> <text class="{{active === true ? '': 'on'}}" bindtap="outBtn">我抽到的纸条</text></view>
2、前端 for 循环出每个数据进行展示。dataList 为在数据库查出来的数据,指明 wx:key
。
<view class="put" wx:for="{{dataListPut}}" wx:key="_id" > <view class="putTop"> <view class="putTopImg"> <image src="{{item.picture}}"></image> </view> <view class="putTopDes"> <text>交友宣言:</text>{{item.des}} </view> </view> </view>
在删除时需要数据的 _id
,所以需要配合 JS 进行传递参数:data-id="{{item._id}}"
。
<view class="putBottom"> <text>{{schoolList[item.location]}}</text> <text>{{item.sex == 1? '男': '女'}}</text> <text class="putBottomDelete" bindtap="deletePut" data-id="{{item._id}}">删除 !</text></view>
通过 e.target.dataset.id
获取到传递过来的参数。
deletePut: function(e){ const that = this const _id = e.target.dataset.id
3、实现交友宣言的3行,超出则用省略号展示。
代码语言:javascript复制.outTopDes_1{ height: 15vh; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; word-break: break-all;}
4、前端判断是否有数据,没有数据则显示“空空如也”。
代码语言:javascript复制<view class="kong" wx:if="{{active === true? true: false}}" hidden="{{dataListPut.length == 0 ? false: true}}">空空如也</view><view class="kong" wx:else hidden="{{dataListOut.length == 0 ? false: true}}">空空如也</view>
我抽到的纸条页面设计
1、基本跟“我放入的纸条”页面相同。多出了微信号的展示位置,交友宣言的行数减少一行。微信号的居中显示:
代码语言:javascript复制.outTopDes_2{ color: rgb(62, 88, 238); text-align: center; font-size: 35rpx;}
2、用户上传的图片可在云开发控制台 > 存储 > 存储管理页面中获取。
步骤5:我的纸条页面逻辑处理
操作步骤
1、data 数据的设计。
代码语言:javascript复制active: true, // 用来改变当前选中的样式 dataListPut: [], // 用来存put页面的数据 dataListOut: [], schoolList: ["河南理工", "河南师范", "焦作师范"]
2、onload 生命周期的设计。
- 因为这个页面没有获取用户 openId 的功能,所以需要先判断下是否已经获取到了用户的 openId。如果没有,则直接跳到 index 页面获取 openId,并提示相应错误。
if(app.globalData.openId == ''){ wx.switchTab({ url: '/pages/index/index', success: res => { }, fail: err => { wx.showToast({ title: err, icon: 'error' }) } }) }
- 调用请求“我放入的纸条”的数据函数。
that.getPutData()
3、通过小程序开放文档提供查询方式,用用户的 openId 来获取到数据,并且把获取到的数据,通过 that.setData 给到 dataListPut 供页面渲染。
查询方法 | 作用 |
---|---|
limit | 来限制获取数据的条数 |
orderBy | 数据排序 |
// 获取数据put getPutData: function(e){ const that = this db.collection('body_girl_yun').where({ openId: app.globalData.openId }).limit(10).orderBy('time', 'desc').get().then(res => { console.log(res) if(res.data.length == 0){ that.setData({ dataListPut: res.data }) return wx.showToast({ title: '没有数据', icon: 'none' }) } that.setData({ dataListPut: res.data }) }).catch(err=>{ wx.showToast({ title: '加载数据失败', icon: 'error' }) }) },
4、删除纸条的逻辑实现。
- 实现删除提示。
wx.showModal({ title: '提示', // content: '确认删除纸条?', content: '删除后友友大厅将不可见,确认?', success (res) {
})
- 如果用户确认删除,用 remove 通过前端传过来的
_id
,对应唯一一个数据,进行删除,包括基本的错误处理。否则提示取消删除。
if (res.confirm) { db.collection("body_girl_yun").where({ _id: _id }).remove().then(res => { wx.hideLoading() if(res.errMsg == 'collection.remove:ok'){ that.getPutData() }else{ wx.showToast({ title: '删除失败', icon: 'error', mask: true }) } }).catch( console.error )} else if (res.cancel) { wx.showToast({ title: '删除取消', icon: 'error', mask: true })}}
5、进行分页查询结合上划触底加载数据。
- 通过 onReachBottom 触发事件。
/** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { if(this.data.active==true){ this.getPutDataBottom() }else{ this.getOutDataBottom() } },
- 通过
skip(pagePut * 10).limit(10)
中的pagePut
参数来记录页数。 - 通过 concat 进行新旧数据的拼接,并更新到页面。
// 上划触底的事件getPutDataBottom: function(){ const that = this let pagePut = that.data.pagePut 1
db.collection('body_girl_yun').where({ openId: app.globalData.openId }).skip(pagePut * 10).limit(10).orderBy('time', 'desc').get().then(res => { console.log(res) wx.hideLoading() // 如果还有数据 if(res.data.length > 0){ // 通过concat进行数据的拼接 let all_data = that.data.dataListPut.concat(res.data) that.setData({ dataListPut: all_data, pagePut: pagePut }) }else{ wx.hideLoading() wx.showToast({ title: '没有更多数据', icon: 'none' }) }
})},
6、实现下拉刷新数据。
- 需要先在 app.json 文件里配置开启下拉刷新功能 enablePullDownRefresh。
"window": { "backgroundColor": "#FFCCFF", "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#FFCCFF", "navigationBarTitleText": "校园交U", "navigationBarTextStyle": "black", "enablePullDownRefresh": true },
- 用户 onPullDownRefresh 下拉触发请求数据的函数,重新获取数据。
/** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { if(this.data.active == true){ this.getPutData("pull") }else{ this.getOutData("pull") } },
步骤6:细节补充
操作步骤
1、加上删除纸条的 showLoading 效果。
代码语言:javascript复制wx.showLoading({ title: '删除中', mask: true})
还有获取 put 数据的 showLoading 等。
2、加上 showModal 提示。
代码语言:javascript复制wx.showModal({ title: '提示', content: '确认删除纸条?', success (res) {
})
至此,该小程序的全部功能已实现完成。更多详情请参见 示例代码。
示例代码:
https://gitee.com/hhh3167253066/school_friends
- End -
推荐阅读:
微擎系统已支持一键部署至云托管
信通院携手微信、腾讯云,正式推出“小程序全链路压力测试专项”服务
关于云开发
云开发平台是帮助企业在云端开发、部署和运行应用的一站式云原生平台。其安全接入、可靠运行的特性已得到220万开发者的信赖,目前已拥有云开发、云托管、微搭低代码、云开发原生网关等面向不同开发场景的产品。
云开发平台具备弹性伸缩免运维等 Serverless 能力,同时作为腾讯生态连接器,连接了腾讯文档、腾讯会议、企业微信等生态产品,帮助企业定制开发更轻松,助力业绩增长。