云开发的初始化配置
主要的2个参数:env
:传入自己的环境ID、traceUser
:是否跟踪用户;
// app.js
App({
onLaunch: function () {
// 1.判断是否具有云开发的能力
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力');
} else {
// 如果有云开发能力,就进行初始化
wx.cloud.init({
// env 参数说明:
// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
// env: 'my-env-id',
env:"cloud1-9gzszx3828cfc3a2",
traceUser: true, // 是否跟踪用户,可以查看访问用户列表
});
}
this.globalData = {};
}
});
为什么小程序的所有代码,都可以在云开发中使用?在project.config.json
中有配置过小程序的根目录、云函数的根目录的信息:
云数据库
文档型数据库存储JSON格式对象会非常的方便,而关系型数据库则不同,关系型数据库是通过表来实现存储的,再维护表与表之间关系的时候会比较麻烦;
典型的文档型数据库:MongoDB
,本质是一个数据库软件,可以创建很多数据库,每个数据库叫database
,里面存储着集合collection
,可以理解为数组,里面存储着记录record/文档doc
,也就是对象,里面的field
对应着对象中的key
;
增
向云数据库中添加一条数据:
//cloud-database:
<button bindtap="onAddDataTap"></button>
Page({
onAddDataTap(){
1.首先获取对应的数据库(获取当前环境的数据库,在app.js中初始化的)
const db = wx.cloud.database()
2.获取数据库集合(collection),传入集合名
const studentCollection = db.collection("studnets")
3.对集合进行新增操作:
studentCollection.add({
//所有添加的数据,都存储在data中
data:{
name:"coder",
age:25,
address:{
name:"南京",
code:13500,
alias:"南哥"
},
hobbies:["鸭子","皮肚"]
},
success:(res)=>{
//成功的回调,返回结果
console.log(res)
}
})
或者通过Promise获取结果:
studentCollection.add({
...和上方类似的添加数据,此处省略
}).then(res=>{
console.log(res);
})
}
.................................
通过async和await代替promise
async onAddDataTap(){
...获取数据库
...获取数据库集合
await studentCollection({
...添加数据操作
})
}
})
动态获取数据插入
const db = wx.cloud.database()
//取集合
const lolCol = db.collection("LOL")
lolCol.add({
data:{
...添加的数据
}
})
onAddLOLDataTap(){
//获取数据
for(let i = 0;i<10;i++){
wx.request({
url:'',
data:{
type:"LOL",
page:i+1
},
success:(res)=>{
const list = res.data.list
this.handleLOLList(list)
}
})
}
},
handleLOLList(list){
for(const item of list){
// add 是云数据库自带的方法
lolCol.add({data:item}).then((res)=>{
插入成功:
})
}
}
删除数据
前提是删除列表中的数据,因此要知道这个列表的id,也就是唯一标识
onDeleteDataTap(){
//明确的会删除某一条数据,通过doc方法,然后传入docID
studentCollection.doc(.docid.).remove().then(res=>{
...被删除的数据
})
}
如果删除失败,需要设置权限:
上方是明确的删除一条数据,现在我们根据条件删除:
需要使用到处查询指令
const db = wx.cloud.database()
//取集合
const studentCollection = db.collection("student")
onDeleteDataTap(){
const cmd = db.command
studentCollection.where({
age:cmd.gt(25) //年龄大于25
}).remove().then(res=>{
console.log(res) //可以删除,但是会报警告,并且提示很差
})
}
通过xx.command来拿到对应的方法:gt(x)用来筛选大于x的,lt(x)用来筛选小于x的;
更新操作
onUpdateDataTap(){
//update的方式
//通过doc()先拿到具体的某一条数据
studentCollection.doc("").update({
data:{
//更新一下之前data中存储的数据
age:30
}
}).then(res=>{
更新成功
})
}
更新也可以通过set来实现,但是会把之前的所有数据全部替换为修改后的,而update只会覆盖而已;
studentCollection.doc("").set({
data:{
age:30
}
})
一次性更新多条数据
const cmd = db.command
studentCollection.where({
age:cmd.gt(25)
}).update({
data:{
age:10
}
}).then(res=>{
console.log(res)
})
以前小程序是不支持一下更新这么多数据的,需要在云函数中定义好对应的方法,然后再调用云函数才可以,因此我们这样更新多条数据的支持性不高
查询数据
根据id查询精确一条数据
get()表示获取数据,通过res.data
拿到
const db = wx.cloud.database()
onQueryDataTap(){
//第一步永远都是拿到集合
const lolCol = db.collection("LOL")
//根据id查询某条数据
lolCol.doc("").get().then(res=>{
console.log(res.data)
})
}
根据条件查询满足条件数据
where条件返回的都是一个数组!!
lolCol.where({
//必须是精确,完全匹配
nickname:"xxx"
}).get().then(res=>{
console.log(res.data)
})
通过指令过滤数据
想要使用指令,前提就是要db.command
,但是这一次返回的最多只有20条数据,想要获取更多需要进行分页查询;
const cmd = db.command
lolCol.where({
//比xx小于等于的rid
rid:cmd.lte(xxx)
}).get().then(res=>{
console.log(res.data);
})
name:cmd.in(['aaa','bbb','ccc'])
只要name在其中某个值就可以查询出来;
通过正则表达式匹配数据
lolCol.where({
nickname:db.RegExp({
//写上规则,准备匹配名字中包含2-3个z
regexp:"z{2,3}",
options:"i" //i标识忽略大小写;
})
})
developers.weixin.qq.com/miniprogram…
获取整个集合的数据
小程序端最多一次性20条,但是在云函数中可以获取100条
分页:skip(offset)
/limit(size)
//这种只能拿20条数据,并且是前20条数据
lolCol.get().then(res=>{
})
lolCol.skip(0).limit(5).get().then(res=>{
拿到前5条数据
})
let page = 1
lolCol.skip(page*5).limit(5).get().then(res=>{
偏移5条
})
排序:orderBy('xx')
//通过rid 字段来排序并且返回升序结果
//升序:asc、降序:desc
lolCol.skip().limit(5).ordeBy("rid","asc").get().then(res=>{
})
lolCol.field({
//过滤,只返回指定的字段的数据
_id:true,
}).skip().limit(5).orderBy("rid","asc").get().then(res=>{
...
})
总结:
// pages/cloud-database/cloud-database.js
// 1.获取对应的数据库
const db = wx.cloud.database()
// 2.获取到操作的集合(collection)
const studentCol = db.collection("students")
Page({
// 向云数据库中添加一条数据:add()
onAddDataTap(){
studentCol.add({
data:{
name:"james",
age:25,
address:{
name:"洛杉矶",
aeg:35,
alias:"lsj"
},
hobbies:["篮球","橄榄球"]
}
}),
//#region success回调函数获取成功的结果
// success:(res)=>{
// wx.showToast({
// title: '成功',
// })
// }
//#endregion
// Promise获取成功的结果
studentCol.add({
data:{
name:"库里",
age:25,
address:{
name:"金州",
aeg:35,
alias:"金州勇士"
},
hobbies:["篮球","高尔夫球"]
},
}).then(res=>{
console.log(res);
})
},
//#region
// 实际上小程序是不建议这样删除的,他更推荐的是在云函数中书写删除方法,然后本地通过调用云函数来实现删除,然后将返回的结果返回给小程序端;
//#endregion
onDeleteDataTap(){
// 1.向云数据库中(该数据的id号)删除一条数据:doc()+remove();其中doc()是找到具体某一个数据
studentCol.doc("id").remove().then(res=>{})
// 2.根据条件,查询到数据的结果,将对应的数据删除掉
const cmd = db.command
studentCol.where({
// 年龄大于25:需要通过内置API(查询指令)实现:
age:cmd.gt(25)
}).remove().then(res=>{
})
},
onUpdateDataTap(){
//#region 1.update的方式:只会更新指定的数据(字段)
studentCol.doc("id").update({
data:{
// 将age修改为30
age:30
}.then(res=>{
console.log(res);
})
})
//#endregion
//#region 2.set的方式:会覆盖掉原来所有的数据,只留下更新后的数据(整个数据)
studentCol.doc("id").set({
data:{
age:30
}
}).then(res=>{
console.log(res);
})
//#endregion
//#region 3.更新多条数据:先拿到符合条件的数据,然后对这些数据进行更新
const cmd = db.command
studentCol.where({
age:cmd.gt(25)
}).update({
data:{
age:10
}
}).then(res=>{})
//#endregion
},
// 查询:小程序一次性最多返回20条数据,而云函数可以返回100条
onQueryDataTap(){
//#region 1.根据id查询某条数据:通过get()获取
studentCol.doc("id").get().then(res=>{
console.log(res);
})
//#endregion
//#region 2.根据条件查询,多条数据
studentCol.where({
// 完完全全匹配到name只为詹姆斯的数据,只要是where条件返回的数据,全部都是数组类型!
name:"詹姆斯"
}).get().then(res=>{
console.log(res);
})
//#endregion
//#region 3.查询指令:gt/lt/gte/lte--》大于小于/大于等于、小于等于
const cmd = db.command
studentCol.where({
age:cmd.lte(18)
}).get().then(res=>{})
//#endregion
//#region 4.正则表达式(模糊查询)
studentCol.where({
name:db.RegExp({
// 书写规则:只匹配到name中含有z的数据并忽略大小写
regexp:"z",
options:"i",
}).get().then(res=>{})
})
//#endregion
//#region 5.获取整个集合中的数据:get()默认就是从头到尾拿到所有的数据(但是一次性最多只能拿到20条,除非在云函数中)
studentCol.get().then(res=>{})
//#endregion
//#region 6.分页:skip(和offset类似)/limit(和size类似)
// 跳过0条数据,拿到5条数据:即前五条数据
studentCol.skip(0).limit(5).get().then(res=>{})
//#endregion
//#region 7.排序orderBy("age")根据年龄来排序
// 必须还要指定:升序:asc 或 降序:desc
let page = 1
studentCol.skip(page*5).limit(5).orderBy("age","asc").get().then(res=>{
console.log(res);
})
// 还可以过滤字段:
studentCol.field({
// 想要什么字段,就设置该字段为true
name:true,
age:true,
address:true,
}).skip(0).limit(5).orderBy("age","desc").get().then(res=>{
console.log(res);
})
//#endregion
},
})
LOL案例练习:
<!--pages/lol-live/lol-live.wxml-->
<view class="list">
<block wx:for="{{lolList}}" wx:key="rid">
<view class="control">
<button size="mini" bindtap="onItemDeleteTap" data-item="{{item}}" data-index="{{index}}">删除</button>
<button size="mini" bindtap="onItemUpdateTap" data-item="{{item}}" data-index="{{index}}">修改</button>
</view>
</block>
</view>
// pages/lol-live/lol-live.js
const db = wx.cloud.database()
const lolCol = db.collection("lol")
Page({
data:{
lolList:[],
offset:0,
size:10
},
onLoad(){
this.fetchLOLData()
},
// 获取数据
fetchLOLData(){
lolCol.skip(this.data.offset).limit(10).get().then(res=>{
const newLOLList = [...this.data.lolList,...res.data]
this.setData({lolList:newLOLList})
this.data.offset = this.data.lolList.length
})
},
// 内置API,滚动到底部触发:
onReachBottom(){
this.fetchLOLData()
},
async onItemDeleteTap(event){
// 1.将数据库中的这条数据删除掉
const {item,index} = event.currentTarget.dataset
const res = await lolCol.doc(item._id).remove()
// 2.获取到结果:请求到被删除后的数据,而不是简单的说一下删除成功
if(res){
// 先将请求到本地存储的数据清空一下,然后重新请求,拿到被删除后的数据
this.setData({lolList:[],offset:0})
this.fetchLOLData()
}
},
})
云存储
拷贝id,就可以在wxml
中使用了
文件上传:
// pages/cloud-storage/cloud-storage.js
Page({
data:{
fileID:""
},
async onUploadTap(){
// 1.选中本地的文件(从相册/拍照)
const imageRes = await wx.chooseMedia({
type:"image"
})
// 2.获取照片
const imagePath = imageRes.tempFiles[0].tempFilePath
// 图片的名称:动态:上传时间+openid+后缀名
const timeStamp = new Date().getTime()
const openid = "open_xx"
// pop():移除最后一个元素并返回
const extension = imagePath.split(".").pop()
const imageName = `${timeStamp}_${openid}.${extension}`
// 3.将这张照片上传到云存储中
const uploadRes = await wx.cloud.uploadFile({
filePath:imagePath,
// 图片的名字设置,是必传的,并且避免图片名重复出现(最好动态生成)
// cloudPath:"abc.jpg"
// 上传到指定文件夹,注意前面不需要加上/
cloudPath:"nba/"+imageName
})
console.log(uploadRes);
// 将图片上传后得到的ID保存下来,这样在wxml中就可以src="{{fileID}}"使用上传的图片了
this.setData({fileID:uploadRes.fileID})
}
})
文件下载
下载会下载到小程序中(本地)
async onDownloadTap(){
// 1.根据fileID下载图片
const res = await wx.cloud.downloadFile({
fileID:fileID
})
// 拿到下载结果并将图片的路径放到data中,然后在wxml中引入tempFilePath
console.log(res);
this.setData({tempFilePath:res.tempFilePath})
},
async onDeleteTap(){
// 1.删除云存储中的内容
const res = await wx.cloud.deleteFile({
fileList:[
// 存放要删除的图片ID
]
})
console.log(res);
}
获取临时链接
async onTemplateTap(){
// 1.获取临时链接(只会存在2小时)
const res = await wx.cloud.getTempFileURL({
fileList:[
// 存放要获取到的临时文件的fileID
]
})
// 2.获取到结果
console.log(res);
}
云函数和云调用
第一步:
如果不想在系统自带的云函数环境中编写代码,那么当我们自己新建一个文件夹作为云函数环境时,还需要在project.config.json
中标明:
第二步:
为云函数指定环境:如果之前环境中已经配置过相应的云函数,那么当指定环境后,会将之前已经配置过的云函数加载进来;
第三步:
拿到之前编写过的云函数代码:
如果想要删除某个云函数:
新建云函数:云函数环境中是Node环境,最好使用Node的语法,比如少用ES6-Module
编写云函数:编写好后,一定要记住右击文件夹进行【上传并部署】,单单保存是没有用的;这样就可以调用了
调用云函数:返回值是一个Promise
// pages/cloud-function/cloud-function.js
Page({
async onTestTap(){
const res = await wx.cloud.callFunction({
// 指定调用哪个云函数
name:"test",
})
console.log(res);
}
})
云函数的调用和传参:
调用并传参:
async sumTap(){
const num1 = 10
const num2 = 20
// 调用云函数
const res = await wx.cloud.callFunction({
name:"sum",
// 传递参数
data:{
num1,
num2,
}
})
console.log(res);
},
云函数:
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
// 1.获取调用者传来的参数
const num1 = event.num1
const num2 = event.num2
// 2.计算结果并返回
return num1 + num2
}
云端测试和本地测试
云端测试:需要先上传到云端,由于云端测试是不能传递参数的,所以我们要在测试模板中,自己手动书写参数;
不生成调试日志,因此用云端测试的很少,不推荐
本地测试:需要用到server库,要先安装一下node_modules包;然后再次运行项目,控制台中就会生成本地测试日志;或者手动debugger,并且不需要上传云端
云函数-登录操作
登录操作需要通过微信提供的:openid,真实开发中,本地需要通过一个函数拿到code,发送到服务器中,服务器根据code拿到appkey等,然后向微信服务器进行换取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,
}
}
async onGetOpenId(){
const res = await wx.cloud.callFunction({
name:"fetchopenid"
})
console.log(res);
},
此时返回了openid、appid,但是unionid是空的:需要在多个平台中申请账号;
openid用来唯一识别用户,不管用户换没换手机,只要是同一个用户,那么小程序中收藏的歌曲仍然会显示;
unionid:比如从公众号中登录小程序,但是公众号中的openid和小程序中的openid不是同一个,但是unionid是一样的;多平台共享!
appid账号:开发小程序时申请的账号,这个账号同时可以开通小程序、公众号、第三方登录;
其中第三方登录是:在其他app中使用微信登录,openid在此情况下就会不同,那么在此基础上想要唯一识别就会使用unionid赋值给你;多平台共享!
在开发中,openid和unionid都是后端来操作的,这里我们拓展一下即可,因为使用了云服务;
云函数对数据库的操作
使用云函数的好处
- 小程序端对数据库的操作有限制
- 之前的一次性删除/修改多条数据(现在可以了,但是提示不友好)
- 获取小程序端的数据,一次性最大只有20条,而云函数可以有100条
- 在云函数端是可以编写代码逻辑的,层次分明更加友好;
// 操作数据库
exports.main = async (event, context) => {
// 1.获取数据库和集合
const db = cloud.database
const lolCol = db.collection("lol")
// 2.从集合中查询
const res = await lolCol.get()
return res
}
async onGetLoLData(){
const res = await wx.cloud.callFunction({
name:"getlol"
})
console.log(res.data);
// 还可以返回一个对象形式
return {
name:"英雄联盟",
data:res.data
}
}
也可以在云函数中进行调用时的筛选,简而言之就是云函数非常的灵活,用来弥补小程序的逻辑不足;
云函数发送网络请求
注意要进行序列化:也就是res.data
// 云函数入口文件
const cloud = require('wx-server-sdk')
const axios = require("axios")
cloud.init() // 使用当前云环境
// 网络请求
exports.main = async (event, context) => {
// 1.从服务器中发送请求
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
// 2.对数据进行转换,发给客户端
return res.data
}
async onGetHouseData(){
const res = await wx.cloud.callFunction({
name:"fetchHomeMulData"
})
console.log(res);
}
云调用-生成小程序码
developers.weixin.qq.com/miniprogram…
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init() // 使用当前云环境
// 云函数入口函数
exports.main = async (event, context) => {
// 1.生成小程序码
const res = cloud.openapi.wxacode.createQRCode({
width:320,
path:"pages/cloud-database/index"
})
// 2.获取到数据,并且上传到云存储中
const wxContext = cloud.getWXContext()
const timestamp = new Date().getTime()
const openid = wxContext.OPENID
const extension = res.contentType.split("/").pop()
const cloudPath = `${timestamp}_${openid}.${extension}`
const qrRes = await cloud.uploadFile({
// 这里不能用filepath,而是要通过fileContent
fileContent:res.buffer,
// 命名
cloudPath
})
return qrRes
}
async onGetMiniData(){
const res = await wx.cloud.callFunction({
name:"getCode"
})
// 然后就可以在wxml中使用image src="qrCodeFileID"
this.setData({qrCodeFileID:res.result.fileID})
}