微信小程序 之 云开发

一、概念
1. 传统开发模式


2. 新开发模式 ( 云开发模式 )

3. 传统、云开发的模式对比

4. 传统、云开发的项目流程对比

5. 云开发的定位
1. 个人的项目或者想法,不想开发服务器,直接使用云开发
2. 某些公司的小程序项目是使用云开发的,但是不多,大部分还是用自己的服务器
3. 可以让我们了解一些云开发的思想,比如服务器、数据库、存储,有利于之后学习服务器相关知识
6. 云开发核心技术
云开发主要包含三大核心技术 : 云数据库、云存储、云函数
云数据库
提供在小程序端直接对数据库进行增删改查的能力
数据库是类似于MongoDB的文档存储的数据库,操作非常方便
非常简单,不是关系数据库,可以直接往里面存储JSON对象
云存储
可以在小程序端直接上传、下载、删除文件
自带CDN,提高文件访问速度
可以获取临时链接,支持在小程序外访问
云函数
提供了在服务器代码的执行能力
包含微信天然的私有鉴权
更大权限的操作数据库等
进行云调用、HTTP请求等操作
二、创建云开发项目
1. 创建项目

2. 了解云开发
01 - 打开云开发

02 - 创建云开发环境

新建新环境
设置 – 环境名称 – 创建环境
03 - 云开发控制台
运营分析
数据库(云数据库)
存储(云存储)
云函数

04 - 环境与配额
环境
一个环境对应一整套独立的云开发资源,包括数据库、存储空间、云函数等资源
各个环境是相互独立的,用户开通云开发后即创建了一个环境,默认可拥有最多两个环境
在实际开发中,建议多配备几个环境
测试环境
预发环境
线上环境
配额
可以根据自己的业务量选择对应的更高配额
网址 : 配额
3. 云开发项目初始化
在小程序端开始使用云能力前,需先调用 wx.cloud.init 方法完成云能力初始化

01 - 在app.js 中初始化
// app.js
App({onLaunch: function () {// 1. 判断是否有云开发能力if (!wx.cloud) {console.error('请使用 2.2.3 或以上的基础库以使用云能力');} else {// 2. 初始化云开发wx.cloud.init({/*** env* env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源* 此处请填入环境 ID, 环境 ID 可打开云控制台查看*/env: 'my-env-id',/*** traceUser* 是否要跟踪用户* 打开后,可在 云开发控制台 - 运营分析 - 用户访问,观看到访问列表*/traceUser: true,});}this.globalData = {};}
});
02 - 路径可进行配置

三、云数据库
1. 概念
网址 : 微信开发文档 - 云数据库
数据库介绍
JSON数据库
云开发提供了一个文档型数据库,类似于MongoDB,里面存放的是一条条JSON格式的对象
一个数据库可以包含多个集合,一个集合中包含多个JSON对象

提供方便的API调用:学习这些API即可
提供了小程序端和服务器端(云函数)中调用的区分
数据库集合的权限

若想每个人都 可读 且 可写

2. 操作数据库 – 控制台操作
01 - 打开

02 - 创建集合
相当于是一个数组 []

03 - 创建一条数据 ( 记录 )
相当于是数组 [] 中的一条数据
默认模式

JSON模式

04 - 导入数据

3. 操作数据库 - 代码操作
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const stuCollect = db.collection('students')
增加数据
在数据库中刷新即可看到新增加的数据
ps : 代码添加的数据,_openid字段也会新增上,作为唯一标识
获取操作后的回调结果
基于回调:传入success、fail、complete
基于Promise:使用then、catch、finally
添加单条数据
// 1. 获取对应的数据库
const db = wx.cloud.database()
// 2. 获取到要操作的集合 (collection)
const stuCollect = db.collection('students')Page({// 新增数据addData() {stuCollect.add({// 数据data: {name: '小王',age: 20,hobbies: ['bvvv'],address: {alias: 'HB',name: '湖北',code: '333343'}},// 可以使用回调函数success: ({ errMsg }) => {if (errMsg === 'collection.add:ok') {wx.showToast({title: '添加成功',})}}})// // 也可以使用promise// .then((res) => { console.log(res) })}
})
循环添加数据
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({// 增加数据onAdd() {// 请求10页的数据for (let i = 1; i <= 10; i++) {wx.request({// 测试用途 : 抓取下某鱼的数据url: 'https://m.douyu.com/api/room/list',data: {page: i,type: 'yz'},success: (res) => {const list = res.data.data.listthis.addData(list)}})}},addData(list) {list.forEach(item => {// 循环添加数据yzCollect.add({data: item}).then(() => {console.log(`${item.roomName}:添加成功`);})})},
})
删除数据
根据 id 删除
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const stuCollect = db.collection('students')Page({onDelete() {// 3. 根据id删除某一条数据 => id去数据库里看即可stuCollect.doc('a64480e663f0753e000826875146d365').remove().then(res => {console.log(res);})}
})
根据 条件 删除
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const stuCollect = db.collection('students')Page({// 3. 根据条件删除数据onDelete() {// 删除 名称 => coder 的数据stuCollect.where({name: 'coder'}).remove().then(res => {console.log(res);})// 删除 年龄 => 大于16岁 的数据// 01.拿到查询指令const cmd = db.commandstuCollect.where({// 02.使用查询指令 gt => > lt => <age: cmd.gt(16)}).remove().then(res => {console.log(res);})}
})
修改数据
修改单条数据
更新数据
update : 更新(增加)某一个字段
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const stuCollect = db.collection('students')Page({// 修改onEdit() {stuCollect.doc('632b810463f08152000634f45aa33965')// update : 修改某一个字段.update({data: {age: 99}}).then(res => {console.log(res);})}
})
替换数据
set : 使用新对象替换原来对象
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const stuCollect = db.collection('students')Page({// 修改onEdit() {stuCollect.doc('2cc84e2663ef492f00c7ecda28da87f4')// set : 原数据被全部替换.set({data: {age: 99}}).then(res => {console.log(res);})}
})
修改多条数据
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const stuCollect = db.collection('students')Page({// 修改onEdit() {// 拿到查询指令const cmd = db.commandstuCollect.where({// 条件 : 年龄小于30岁的人age: cmd.lt(30)}).update({data: {age: 20}}).then(res => {console.log(res);})}
})
查找数据
查询数据的方式 :
方式一:通过ID查询精确的某一条数据
使用doc查询ID
方式二:根据条件查询满足条件的数据
使用where作为条件
方式三:通过指令过滤数据
使用db.command的指令
eq => 等于
neq => 不等于
lt => 小于
lte => 小于或等于
gt => 大于
gte => 大于或等于
in => 字段值在给定数组中 ( name : cmd.in['coder','star'] )
nin => 字段值不在给定数组中
方式四:通过正则表达式匹配符合的数据
使用db.RegExp创建正则规则
方式五:获取整个集合的数据(小程序端一次性最多20条,云函数中可以获取100条)
直接调用get
方式六:过滤、分页、排序查询数据
使用field、skip、limit、orderBy
方式一 : 精准查询
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({onQuery() {// 方式一 : 根据id查询某条数据yzCollect.doc('663f243e63f07f9700071256127340a0').get().then(({ data }) => {console.log(data);})}
})
方式二 : 条件查询
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({onQuery() {// 方式二 : 根据条件查询 => 查询到的是多条数据yzCollect.where({// 不是模糊查询,但是可能是同名的nickname: "小野静奈",}).get().then(({ data }) => {console.log(data); // [ {...} ]})}
})
方式三 : 指令查询
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({onQuery() {// 方式三 : 查询指令 => gt => 大于 lt => 小于// 01 - 获取查询指令const _ = db.commandyzCollect.where({// 02 - 使用查询指令rid: _.lt(9000000),}).get().then(({ data }) => {console.log(data); // [ {...},{...} ] 小程序端一次性最多返回20条,可做分页查询})}
})
方式四 : 正则查询
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({onQuery() {// 方式四 : 正则表达式查询 => 查询包含 字母z 的数据 => 模糊查询yzCollect.where({// nickname: db.RegExp({// regexp:'z', // 包含z// options:'i' // 忽略大小写// }),nickname: /z/ig}).get().then(({ data }) => {console.log(data); // [ {...},{...} ] 小程序端一次性最多返回20条,可做分页查询})}
})
方式五 : 集合查询
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({onQuery() {// 方式五 : 获取整个集合中的数据 => 直接getyzCollect.get().then(({ data }) => {console.log(data); // [ {...},{...} ] 小程序端一次性最多返回20条,可做分页查询})}
})
方式六 : 综合查询
// 1. 获取数据库对象
const db = wx.cloud.database()
// 2. 获取操作的集合
const yzCollect = db.collection('YZ')Page({// 方式六 : 综合查询/*** skip => offset偏移量 => 跳过几条数据* limit => size => 拿几条数据* orderBy => 排序('des','方式') => 升序:asc | 降序 : desc* field => 过滤字段 => 拿想要的数据字段*/// onQuery() {// 过滤字段 => 拿 _id,nickname,rid 三个字段.field({_id: true,nickname: true,rid: true})// 跳过0条数据.skip(0)// 拿5条数据.limit(5)// 排序 => 根据rid排序,升序.orderBy('rid', 'asc').get().then(({ data }) => {console.log(data); // [ {_id:'', nickname:'', rid:''},{...} ] })}
})
4. 案例
效果

wxml
<view class="nav"><block wx:for="{{dataList}}"wx:key="index"><view class="item"><view class="notice"><view size="mini"class="btn"bindtap="tabEdit"data-item="{{item}}"data-index="{{index}}">Edit</view><text>{{item.nickname}}</text><view size="mini"class="btn"bindtap="tabDel"data-item="{{item}}"data-index="{{index}}">Del</view></view><image src="{{item.roomSrc}}"mode="widthFix" /></view></block>
</view>
wxss
.nav {padding: 20rpx;display: flex;flex-wrap: wrap;justify-content: space-between;
}.item {width: 48%;margin-bottom: 30rpx;border-radius: 40rpx;
}.notice {font-size: 30rpx;line-height: 40rpx;display: flex;align-items: center;justify-content: space-between;color: pink;
}.btn {font-size: 24rpx;color: gray;
}image {width: 100%;
}
js
// 获取数据库对象
const db = wx.cloud.database()
// 获取集合
const yzCollect = db.collection('YZ')
Page({data: {dataList: [],page: 0,pageSize: 10},onLoad() {this.getDataList()},// 上拉加载更多onReachBottom() {this.getDataList()},/*** 方法*/// 获取数据getDataList() {const { page, pageSize, dataList } = this.datayzCollect.field({nickname: true,roomName: true,roomSrc: true,}).skip(page * pageSize).limit(pageSize).get().then(({ data }) => {console.log(data);// 保存数据this.setData({dataList: [...dataList, ...data]})this.data.page = page + 1})},// 编辑async tabEdit(e) {const { item, index } = e.currentTarget.datasetconst newName = item.nickname + 'Q'// 更改数据库数据const { errMsg } = await yzCollect.doc(item._id).update({data: {nickname: newName}})if (errMsg !== 'document.update:ok') {return wx.showToast({title: '修改失败',icon: 'none'})}// 更改页面中数据this.setData({['dataList[' + index + '].nickname']: newName})wx.showToast({title: '修改成功',icon: 'none'})},// 删除async tabDel(e) {const { item, index } = e.currentTarget.dataset// 删除数据库数据const { errMsg } = await yzCollect.doc(item._id).remove()if (errMsg !== 'document.remove:ok') {return wx.showToast({title: '删除失败',icon: 'none'})}// 删除页面中数据this.data.dataList.splice(index, 1)this.setData({dataList: this.data.dataList})wx.showToast({title: '删除成功',icon: 'none'})// 判断当前页面数量是否小于pageSize,在第一页时可能会出现镂空现象if (this.data.dataList.length < this.data.pageSize) {this.getDataList()}},
})
四、云存储
1. 概念
网址 : 微信开发文档 - 云存储
云存储用于将文件存储到云端 :
云存储提供高可用、高稳定、强安全的云端存储服务
持任意数量和形式的非结构化数据存储,如视频和图片
并在控制台进行可视化管理
云存储常见的操作 :
上传文件到云存储中(图片、视频、音频等等都可以)
获取文件的临时链接(在外网可以访问)
下载文件到本地(本地文件缓存)
将云存储中的文件删除
2. 操作云存储 - 控制台操作
01 - 上传
图片、视频、音频等

02 - 页面展示

3. 操作云存储 - 代码操作
上传操作
Page({data: {imagePath: ""},// 上传文件async onUploadTap() {// 1. 选中本地文件( 相册、拍照 )const { type, errMsg, tempFiles } = await wx.chooseMedia({// 设定一次只能传一张图片count: 0})if (errMsg !== 'chooseMedia:ok') {return wx.showToast({title: '上传失败',})}console.log(type, errMsg, tempFiles);// 2. 获取照片const imagePath = tempFiles[0].tempFilePath// 3. 因为图片名称容易重复,所以这里设定一下const imageName = this.setImageName(imagePath)// 4. 将照片上传到云存储中const uploadRes = await wx.cloud.uploadFile({// 文件路径 => 文件名称,如果在images文件家中,前面带上即可 => images/abc.pngcloudPath: 'images/' + imageName,// 指定要上传的文件的小程序临时文件路径filePath: imagePath,})console.log(uploadRes);if (uploadRes.errMsg !== 'cloud.uploadFile:ok') {return wx.showToast({title: '上传失败',})}wx.showToast({title: '上传成功',})// 5. 页面展示this.setData({imagePath: uploadRes.fileID})},// 图片名称设定setImageName(imagePath) {// 1. 时间戳const timeStamp = new Date().getTime()// 2. openidconst openid = 'openid'// 3. 文件后缀名 pop => 拿到最后一个元素 const extension = imagePath.split(".").pop()// 返回拼接名称return `${timeStamp}_${openid}.${extension}`}
})
下载操作
Page({data: {imagePath: ""},// 一、点击下载onDownload() {// 1. 获取手机相册权限wx.authorize({scope: 'scope.writePhotosAlbum',success: () => {// 2. 从云存储中获取下载的文件路径this.getDownPath()},fail: () => {wx.showToast({title: '未授权,请前往微信设置页面中打开授权',icon: 'none'})}})},// 二、获取下载的文件地址async getDownPath() {// 根据fileID获取下载的文件路径const { errMsg, tempFilePath } = await wx.cloud.downloadFile({// fileIDfileID: "cloud://xuanyu-dev"})if (errMsg !== 'downloadFile:ok') {return wx.showToast({title: '下载失败',icon: 'none'})}// 3. 保存文件到手机相册this.saveFile(tempFilePath)// 也可展示到页面上this.setData({imagePath: tempFilePath})},// 三、保存文件到手机相册saveFile(filePath) {// 下载图片到手机本地wx.saveImageToPhotosAlbum({filePath,success: ({ errMsg }) => {if (errMsg !== 'saveImageToPhotosAlbum:ok') {return wx.showToast({title: '下载失败',icon: 'none'})}wx.showToast({title: '下载成功',icon: 'none'})}})}
})
删除操作
Page({// 点击删除async onDelete() {const { errMsg } = await wx.cloud.deleteFile({fileList: [// fileID'cloud://xuanyu-dev'],})if (errMsg !== 'cloud.deleteFile:ok') {return wx.showToast({title: '删除失败',icon: 'none'})}wx.showToast({title: '删除成功',icon: 'none'})},
})
临时链接
为什么要获取临时链接 :
我们将文件上传到云存储后,可以通过fileID在小程序中直接访问
但是,如果我们希望在小程序以外的地方访问(比如浏览器、手机端),那么fileID是不可以的
这个时候,我们可以通过获取临时链接,该链接可以在小程序以外访问
注意:文件链接有效期为两个小时
Page({// 生成临时文件链接async onTemplate() {// 1. 请求临时链接const { errMsg, fileList } = await wx.cloud.getTempFileURL({fileList: [// fileID'cloud://xuanyu-dev','cloud://xuanyu-dev'],})if (errMsg !== 'cloud.getTempFileURL:ok') {return wx.showToast({title: '生成链接失败',icon: 'none'})}// 2. 获取结果const resUrl = fileList.map(item => {return item.tempFileURL})console.log(resUrl);wx.showToast({title: '生成链接成功',icon: 'none'})},
})
五、云函数和云调用
1. 概念
云函数即在云端(服务器端)运行的函数 :
在物理设计上,一个云函数可由多个文件组成,占用一定量的CPU 内存等计算资源
各云函数完全独立,可分别部署在不同的地区
开发者无需购买、搭建服务器,只需编写函数代码并部署到云端即可在小程序端调用
同时云函数之间也可互相调用
云函数的编写方式 :
一个云函数的写法与一个在本地定义的 JavaScript 方法无异,代码运行在云端 Node.js 中
当云函数被小程序端调用时,定义的代码会被放在Node.js 运行环境中执行
可以如在 Node.js 环境中使用 JavaScript 一样在云函数中进行网络请求等操作,而且还可以通过云函数后端 SDK搭配使用多种服务,比如使用云函数 SDK 中提供的数据库和存储 API 进行数据库和存储的操作
云开发的云函数的独特优势在于与微信登录鉴权的无缝整合 :
当小程序端调用云函数时,云函数的传入参数中会被注入小程序端用户的 openid,开发者无需校验 openid 的正确性因为微信已经完成了这部分鉴权,开发者可以直接使用该 openid
云函数作用 :
在云函数中对云数据库进行操作
对结果进行某种转换,再返回到小程序端
在云函数中对云存储进行操作
进行查询、上传、删除等操作
向其他服务器发送请求
请求到数据后,再返回到小程序端(云函数中对域名、ip没有限制)
. . . . . .
2. 使用过程
01 - 选择环境

02 - 同步云函数

03 - 下载代码到本地

04 - 创建云函数


05 - 编写代码逻辑
// 云函数入口文件
const cloud = require('wx-server-sdk')cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
exports.main = async (event, context) => {return 'hello world'
}
06 - 将云函数上传到云端

07 - 小程序中对云函数调用
Page({async onLoad() {// 1. 调用云函数const { errMsg, requestID, result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'testFunc'})console.log(result); // 'hello world'}
})
3. 基本使用
案例 : 云函数来计算两个数字的和
01 - 本地代码
Page({async onLoad() {// 1. 调用云函数const { errMsg, requestID, result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'testFunc',// 3. 传入数据到云函数data: {num1: 10,num2: 20}})console.log(result); // 30}
})
02 - 云函数代码
// 云函数入口文件
const cloud = require('wx-server-sdk')cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
exports.main = async (event, context) => {// 1. 获取调用者传入的参数,就是在data中传过来的参数// console.log(event); // 因为显示在云端,所以这样是看不到结果的const { num1, num2 } = event// 2. 返回结果return num1 + num2
}
03 - 部署云函数
右键,上传并部署即可
4. 云函数代码调试
云端测试
缺点 : 看不到打印信息
01 - 找到云函数

02 - 云端测试

本地调试
01 - 找到云函数

02 - 本地调试
安装依赖

开启成功

重新请求

更改代码

5. 高级使用
云函数 - 获取openID
微信内部做好了身份鉴权,在云函数中可直接拿到登录者的openID
openid可以用于作为用户身份的标识符,在云开发中可以获取用户openid来验证用户是否已经登录
在云函数中获取微信调用上下文 :
Cloud.getWXContext(): Object
网址 : wxcloud
云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
/*** event : 传递过来的参数* context : node运行环境上下文,一般不会用到*/
exports.main = async (event, context) => {// 1. 获取到微信的上下文const wxContext = cloud.getWXContext()return {event,openid: wxContext.OPENID,appid: wxContext.APPID,unionid: wxContext.UNIONID,}
}
本地调用
Page({async onLoad() {// 1. 调用云函数const { errMsg, requestID, result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'getOpenid',})console.log(errMsg, requestID, result); }
})
云函数 – 操作云数据库
小程序端口对数据库的操作有限制 :
小程序端一次最多获取20条数据 => 云函数最多100条
小程序端一次性删除、修改多条数据可能会报警告 => 云函数中没有限制
云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
exports.main = async (event, context) => {// 1. 获取数据库const db = cloud.database()// 2. 获取集合const _ = db.collection('YZ')// 3. 从集合中查询数据return await _.get()
}
本地调用
Page({async onLoad() {// 1. 调用云函数const { result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'getYZdata',})console.log(result.data); // [{...}, {...}, {...}, ...]}
})
云函数 – 操作云存储
云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
exports.main = async (event, context) => {// 1. 下载操作 => 下载下来文件,不是地址,不知道干嘛用的,又不能保存在本地const { errMsg: downErrMsg, fileContent } = await cloud.downloadFile({// fileIDfileID: "cloud://xuanyu-dev"})if (downErrMsg !== 'downloadFile:ok') {return downErrMsg}// return fileContent.toString('utf8')// 2. 删除操作const { errMsg: delErrMsg } = await cloud.deleteFile({fileList: ['cloud://xuanyu-dev'],})if (delErrMsg !== 'deleteFile:ok') {return delErrMsg}return 'OK'
}
本地调用
Page({data: {qrCodeUrl: ''},async onLoad() {// 1. 调用云函数const { result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'fetchData',})console.log(result);}
})
云函数 – 发送http请求
对于小程序某些域名的限制无法配置时,我们可以通过云函数作为代理来请求数据,再返回给小程序端
需要使用axios,所以需安装
ps :
npm i axios@0.27.2 => 如果安装高版本的,可能会出问题

返回的结果时,如果出现以下问题,可能是格式问题,返回.data或者详细的数据即可

云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
const axios = require('axios')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
exports.main = async (event, context) => {// 1. 从其他服务器中请求数据const res = await axios.get('http://www.baidu.com')// 2. 对数据进行转换// 3. 返回数据到小程序端 => 这里要返回.data 否则可能会报错return res.data
}
本地调用
Page({async onLoad() {// 1. 调用云函数const { result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'fetchData',})console.log(result);}
})
云函数 – 生成小程序码
网址 : 微信官方文档 - 生成二维码

云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境// 云函数入口函数
exports.main = async (event, context) => {// 1. 生成小程序码const { contentType, errMsg: codeErrMsg, buffer } = await cloud.openapi.wxacode.createQRCode({"path": 'pages/cloud-database/index',"width": 320})if (codeErrMsg !== 'openapi.wxacode.createQRCode:ok') {// 生成二维码失败return codeErrMsg}// 2. 获取图片数据,上传到云存储中const timeStamp = new Date().getTime()const openid = cloud.getWXContext().OPENIDconst ext = contentType.split('/').pop()const { errMsg: uploadErrMsg, fileID } = await cloud.uploadFile({// 文件内容,注 : 这里没有filePathfileContent: buffer,cloudPath: `qrcode_${timeStamp}_${openid}.${ext}`});if (uploadErrMsg !== 'uploadFile:ok') {// 存储二维码失败return uploadErrMsg}// return fileID// 可直接返回fileID | 或者多一步,返回临时路径// 3. 获取图片临时路径const { errMsg: getTempErrMsg, fileList } = await cloud.getTempFileURL({fileList: [fileID]})if (getTempErrMsg !== 'getTempFileURL:ok') {// 获取二维码失败return getTempErrMsg}// 4. 返回临时图片路径return fileList[0].tempFileURL
}
本地调用
Page({data: {qrCodeUrl: ''},async onLoad() {// 1. 调用云函数const { result } = await wx.cloud.callFunction({// 2. 指定调用哪个云函数name: 'fetchData',})this.setData({qrCodeUrl: result})console.log(result);}
})
相关文章:

微信小程序 之 云开发
一、概念1. 传统开发模式2. 新开发模式 ( 云开发模式 )3. 传统、云开发的模式对比4. 传统、云开发的项目流程对比5. 云开发的定位1. 个人的项目或者想法,不想开发服务器,直接使用云开发2. 某些公司的小程序项目是使用云开发的,但是不多&#…...

程序员的三门课,学习成长笔记
最近是有了解到一本好书,叫做程序员的三门课在这本书的内容当中我也确实汲取到了很多前辈能够传达出来的很多关于程序员职业规划以及成长路线上的见解,令我受益匪浅,故此想要把阅读完的每一章节结合自己的工作经验做一个精细化的小结…...

[技术经理]01 程序员最优的成长之路是什么?
00前言 谈起程序员的职业规划,针对大部分的职场人士,最优的成长之路应该是走技术管理路线,而不是走技术专家路线。 01关键的一步 中国自古就有“学而优则仕”的传统,发展到今天,在我们的现代企业里面,尤…...

linux集群技术(三)--七层负载均衡-nginx
nginx特点nginx优势、缺点生产架构nginx 7层负载均衡语法示例nginx负载均衡算法测试案例生产案例 1.nginx特点 1. 功能强大,性能卓越,运行稳定。 2. 配置简单灵活。 3. 能够自动剔除工作不正常的后端服务器。 4. 上传文件使用异步模式。client---nginx---web1 web2 web3 lvs同…...

阿里云物联网平台设备模拟器
在使用阿里云物联网平台过程中,如果开始调试没有实际的物理设备,可以考虑在阿里云物联网平台使用官方自带的模拟器进行调试。不过也可以通过叶帆科技开发的阿里云物联网平台设备模拟器AliIoTSimulator进行调试,AliIoTSimulator可以独立运行&a…...

docker全解
目录说明docker简介为什么是docker容器与虚拟机比较容器发展简史传统虚拟机技术容器虚拟化技术docker能干什么带来技术职级的变化开发/运维(Devops)新一代开发工程师Docker应用场景why docker?docker的优势docker和dockerHub官网Docker安装CentOS Docker…...

Vue3 基础
Vue3 基础 概述 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面&…...

【Linux】冯.诺依曼体系结构与操作系统
环境:centos7.6,腾讯云服务器Linux文章都放在了专栏:【Linux】欢迎支持订阅🌹冯.诺依曼体系结构什么是冯诺依曼体系结构?我们如今的计算机比如笔记本,或者是服务器,基本上都遵循冯诺依曼体系结构…...

WSO2 apim 多租户来区分api
WSO2 apim 多租户来区分api1. Tenant1.1 Add new tenant1.2 Add Role/User1.3 Published Api2. Delete Teant3. AwakeningWSO2安装使用的全过程详解: https://blog.csdn.net/weixin_43916074/article/details/127987099. Official Document: Managing Tenants. 1. Tenant 1.1 …...

TodoList(Vue前端经典项目)
TodoList主要是包含了CRUD功能,本地存储功能(loaclStorage)总结:全选按纽可以通过forEach循环来讲数据中的isCheck中的false删除实现就通过传递id,然后根据filter循环将符合条件的数据返回成数组,然后将返回…...

【扫盲】数字货币科普对于完全不了解啥叫比特币的小伙伴需要的聊天谈资
很多人并不清楚,我们时常听说的比特币,以太坊币,等等这些东西到底是一场骗局还是一场货币革命? 下面就围绕这数字货币的历史以及一些应用场景开始分析这个问题。 一、 开端 一切从2008年中本聪(Satoshi Nakamoto&…...

算法学习笔记:双指针
前言: 用于记录总结刷题过程中遇到的同类型问题 双指针问题及用法总结 1. 总结 双指针常用于遍历连序性对象(如数组、链表等)时,使用两个或多个指针进行单向遍历及相应的操作。避免多层循环,降低算法的时间复杂度。 …...

C++类的静态成员总结
tags: C OOP 引子: 类为什么需要静态成员 有时候类需要与它的一些成员与类本身直接相关, 而不是与类的各个对象都保持关联, 这就减少了成员与每一个类的实例对象的联系, 从而降低资源占用. 另一方面, 如果每次都需要重新更新该成员, 使得对象使用新的值, 这时候只需要修改一份…...

二、并发编程的三大特性
文章目录并发编程的三大特性1、原子性什么是并发编程的原子性?保证并发编程的原子性synchronizedCASLock锁ThreadLocal2、可见性什么是可见性?解决可见性的方式volatilesynchronizedLockfinal3、有序性什么是有序性?as-if-serialhappens-beforevolatile并发编程的…...

Ubuntu 22.04.2 LTS安装Apollo8.0
本人硬件环境: CPU:Intel Core i7 6700 显卡(GPU):NVIDIA GTX 3080 10G 内存:SAMSUNG DDR4 32GB 硬盘:双SSD系统盘 2T,双系统(windows,ubuntu) 一、安装Ubuntu 22.04…...

提高转化率的 3 个客户引导最佳实践
如果您的试用客户没有转化为付费客户,或者您总体上正在努力解决试用到付费转化率,那么您来对地方了。本文的最终目标是向您展示一些可用于提高自己的激活率和整体试用到付费转化的最佳客户引导实践。SaaS公司目前生活在一个以产品为主导的增长时代。换句…...

【消费战略】解读100个食品品牌丨元气森林 6年百亿的饮品黑马成功之道
元气森林成立于2016年,短短六年时间取得了近百亿营收的奇迹,成为让可口可乐、百事、娃哈哈、农夫山泉等消费巨头都无法忽视的对手。六年的成长堪比行业前辈20多年的积累,从这个角度而言,塔望咨询认为元气森林是成功的,…...

b2b b2c o2o分布式电子商务平台源码 mybatis+spring cloud
鸿鹄云商大型企业分布式互联网电子商务平台,推出PC微信APP云服务的云商平台系统,其中包括B2B、B2C、C2C、O2O、新零售、直播电商等子平台。 分布式、微服务、云架构电子商务平台 java b2b2c o2o 技术解决方案 开发语言: java、j2ee 数据库&am…...

LeetCode104_104. 二叉树的最大深度
LeetCode104_104. 二叉树的最大深度 一、描述 给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 3/ \9 …...

浏览器跨域问题
跨域问题什么是跨域问题如何解决跨域问题JSONPCORS方式解决跨域使用 Nginx 反向代理使用 WebSocket跨源请求是否能携带Cookie什么是跨域问题 跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制,它的初衷是为…...

面向对象的三特性
继承Java中通过继承,子类可以获取父类的属性和方法,不需要自己去定义即可获取,可以提高代码的复用性;同时,子类如果对继承的方法不满意,可以自己重写方法,进行个性化定制。好处:提高…...

管理者如何给员工沟通绩效
目录 1.沟通基础 2.聊绩效第一部分,心理预期管理 3.聊绩效第二部分,分人沟通 3.1 高绩效者 3.2 中绩效者 3.3 低绩效者 4.注意 1.沟通基础 无论在哪里工作,每个员工都不免会遇到绩效沟通的事情。作为管理层,通过每年的绩效…...

使用Python启动appium
import osimport subprocessimport multiprocessingimport timeimport pytestfrom appium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom time import sleep# 关于appium的启动# 1、桌面版(咱们现在用的):…...

活动回顾丨研发效能度量线下沙龙圆满举办
2月18日,由跬智信息(Kyligence)联合甄知科技主办的研发效能度量线下沙龙圆满举办。本次沙龙在 Kyligence 上海总部举办,Kyligence 联合创始人兼 CTO 李扬、腾讯 Tech Lead 茹炳晟,以及甄知科技创始人兼 CTO 张礼军在现…...

问题解决篇 | Win11网络连接上了但是无法上网(修改DNS弹出框框“出现问题”,如何通过网络检测确定并修复网络问题)
目录 问题 网络诊断 Win i 打开设置 搜索“查找并修复网络问题”并点击 "远程计算机或设备将不接受连接" 解决办法: Win R,输入 inetcpl.cpl ,点击确定,打开Internet选项 选择“连接” 点击“局域网设置” 三个…...

Go语言进阶与依赖管理-学习笔记
1 语言进阶 1.1 Goroutine 线程:内核态,栈MB级别 协程:用户态,轻量级线程,栈KB级 1.2 CSP 提倡通信实现共享内存 1.3 Channel 创建方法 make(chan 元素类型,缓冲区大小) 无缓冲通道&#x…...

【Mybatis源码分析】datasource配置${}表达式时是如何被解析的?
核心配置中${}表达式配置的解析一、核心配置主体二、核心配置文件中properties是如何被解析的?三、${} 表达式的解析四、总结前提: 核心配置文件是被XMLConfigBuilder 对象进行解析的,configuration 对象是由它父类BaseBuider继承下来的属性…...

网络基础概述
1.计算机网络背景 计算机刚刚发展的时候,是没有网络的,每一台计算机都是相互独立的。后来,人们有了多人协作的需求,人们就想办法把多台计算机用“线”连接起来,实现数据共享。后来,连接到一起的电脑越来…...

微搭使用笔记(四) 通过循环展示组件+json配置生成表单及数据获取
背景及整体思路 上篇文章我们通过微搭提供的数据模型完成了问卷表单页面的创建和数据采集,相对来说除了数据模型配置略显复杂外其他的倒还算方便。 本文我们通过for循环加上json文件配置的方式实现一个通用表单页面,如果更换了表单只需要替换掉json配置…...

做测试5年,靠业务熟悉吃老本,技术短板暴露,30岁被无情辞退...
朋友跟我诉苦,最近他被公司无情辞退了。测试几年,月薪10k,如今已经30了,接下来不知道该怎么办,让我帮他想想办法... 几年下来,也算是公司的骨干成员,不说有功,但一定无过。公司业务…...