微信云开发是微信小程序推出来挺久的功能了,最近看了下云开发文档,准备动手写个小程序练练手。
前端模块使用以前写过的一个用uni-app搭建的一个项目,云开发模块就是重新搭建。
首先在微信开发工具创建小程序,填入你的appid,后端服务选择小程序云开发。
创建完毕,目录结构如下:
cloudfunctions
是云函数目录,miniprogram
是小程序前端模块。
因为前端模块我要使用uni-app,所以得进行改造。
把miniprogram
目录删除,把 vue-cli 创建 uni-app 项目代码复制进来,不懂怎么创建uni-app项目的点这里。
安装依赖npm i
,运行npm run dev:mp-weixin
,最终目录如下:
修改uni-app的打包输出路径:
dev 模式编译出的各平台代码存放于根目录下的 /dist/dev/目录下,
build 模式编译出的各平台代码存放于根目录下的 /dist/build/ 目录下,
对于要固定的小程序目录很不友好,我们得固定输出目录。
修改package.json
的scripts
的 dev:mp-weixin
和build:mp-weixin
命令:
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin UNI_OUTPUT_DIR=dist/build/mp-weixin vue-cli-service uni-build",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin UNI_OUTPUT_DIR=dist/build/mp-weixin vue-cli-service uni-build --watch",
添加UNI_OUTPUT_DIR=dist/build/mp-weixin
,指定输出目录为dist/build/mp-weixin
再修改project.config.json
文件,把前端模块指定到dist/build/mp-weixin
:
"miniprogramRoot": "dist/build/mp-weixin/",
修改完成,打开微信开发工具,小程序就可以运行了。
在云开发设置面板,新建个环境,后面的env取环境ID
在src/main.js 添加初始化方法
wx.cloud.init({
env: '5175aa', //环境
traceUser: true, //是否在将用户访问记录到用户管理中,在控制台中可见
})
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
// env: cloud.DYNAMIC_CURRENT_ENV
env: '5175aa'
})
我们把cloudfunctions
文件夹下的文件都删除,新建个main
云函数:
config.json
{
"permissions": {
"openapi": []
}
}
package.json
{
"name": "echo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~2.4.0"
}
}
index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
// API 调用都保持和云函数当前所在环境一致
// env: cloud.DYNAMIC_CURRENT_ENV
env: '5175aa'
})
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
}
一个云函数就完成了,我们现在可以进行本地调试,或者上传到云端部署。
需要进入cloudfunctions/main
目录下,安装依赖 npm i
再右键选择开启云函数本地调试
wx.cloud.callFunction({
// 云函数名称
name: 'mian',
// 传给云函数的参数
data: {
a: 1,
b: 2,
},
success: function(res) {
console.log(res.result.sum) // 3
},
fail: console.error
})
当然,Promise 风格的调用也是支持的:
wx.cloud.callFunction({
// 云函数名称
name: 'main',
// 传给云函数的参数
data: {
a: 1,
b: 2,
},
})
.then(res => {
console.log(res.result) // 3
})
.catch(console.error)
请求成功。
云函数也有不少缺点:
package.json
所以我们需要用tcb-router
进行优化,tcb-router
是一个koa风格的云函数路由库。
tcb-router
:在cloudfunctions/main
目录下
npm i tcb-router -S
cloudfunctions/main/index.js
修改成:const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router')
cloud.init({
// API 调用都保持和云函数当前所在环境一致
// env: cloud.DYNAMIC_CURRENT_ENV
env: '5175aa'
})
// 云函数入口函数
exports.main = async(event, context) => {
const app = new TcbRouter({
event
})
//全局中间件
app.use(async(ctx, next) => {
console.log('进入全局中间件')
await next()
console.log('退出全局中间件')
})
app.router('add', async(ctx, next) => {
ctx.body = {
data: '新增成功'
}
})
app.router('movie', async(ctx, next) => {
ctx.body = {
data: '输出'
}
})
return app.serve()
}
wx.cloud.callFunction({
name: 'main',
data: {
$url: 'add'
},
}).then((res) => {
console.log(res)
})
wx.cloud.callFunction({
name: 'main',
data: {
$url: 'movie'
},
}).then((res) => {
console.log(res)
})
我们可以把路由的实现抽离成一个个js文件:
在cloudfunctions/main
下新建common/index.js
exports.login = async (ctx, next) => {
console.log(ctx.cloud)
console.log(ctx.db)
ctx.body = {
data: '输出'
}
}
在cloudfunctions/main/index.js
中,用require
导入,并且可以把cloud
、db
对象挂载到ctx对象下,在实现模块就可以使用ctx.cloud
、ctx.db
调用对象
// 云函数模板
// 部署:在 cloud-functions/login 文件夹右击选择 “上传并部署”
const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router');
// 公共模块
const common = require('./common/index')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
// env: cloud.DYNAMIC_CURRENT_ENV
env: '5175aa'
})
const db = cloud.database()
exports.main = async (event, context) => {
const app = new TcbRouter({event});
// app.use 表示该中间件会适用于所有的路由
app.use(async (ctx, next) => {
ctx.db = db;
ctx.cloud = cloud;
console.log('进入全局中间件')
await next()
console.log('退出全局中间件')
});
//授权登录
app.router('/login', common.login)
return app.serve();
}
到现在为止,可以进行应用开发了,但使用过koa的人都知道,我们还差个全局异常捕捉中间件,来统一处理服务器报错问题。
新建个工具类utils/index.js
module.exports = {
// 手动报错
throwError(code = 400, msg = '服务器错误') {
const err = new Error(msg);
err.code = code;
err.msg = msg;
throw err;
},
};
在cloudfunctions/main/index.js
const utils = require('./utils/index')
// app.use 表示该中间件会适用于所有的路由
app.use(async (ctx, next) => {
ctx.db = db;
ctx.cloud = cloud;
ctx.utils=utils //挂载工具类
try {
await next(); //在下个环节报错就抛出错误
} catch (err) {
// 手动抛出异常 throwError函数触发
if (err.msg) {
ctx.body = {
code: err.code,
data: '',
msg: err.msg,
};
} else {
//自动报错
ctx.body = {
code: 500,
data: '',
msg: '服务器内部错误:' + err,
};
}
}
});
exports.login = async (ctx, next) => {
ctx.uilts.throwError('500','手动抛出异常')
ctx.body = {
data: '输出'
}
}
返回成功
exports.login = async (ctx, next) => {
console.log(a); //错误 不存在a变量
ctx.body = {
data: '输出'
}
}
返回成功
云开发的数据库,前端和云函数都可以进行操作,但在前端进行数据库操作有比较大的缺点:
所以还是推荐在云函数进行数据库操作。
在云开发面板,新建个集合user(表)
const db = cloud.database()
db.collection('user').add({
// data 字段表示需新增的 JSON 数据
data: {
// _id: 'todo-identifiant-aleatoire', // 可选自定义 _id,在此处场景下用数据库自动分配的就可以了
description: "learn cloud database",
due: new Date("2018-09-01"),
tags: [
"cloud",
"database"
],
// 为待办事项添加一个地理位置(113°E,23°N)
location: new db.Geo.Point(113, 23),
done: false
},
success: function(res) {
// res 是一个对象,其中有 _id 字段标记刚创建的记录的 id
console.log(res)
}
})
db.collection('user').doc('todo-identifiant-aleatoire').get().then(res => {
// res.data 包含该记录的数据
console.log(res.data)
})
我们也可以一次性获取多条记录。通过调用集合上的 where 方法可以指定查询条件,再调用 get 方法即可只返回满足指定查询条件的记录,比如获取用户的所有未完成的待办事项:
db.collection('user').where({
_openid: 'user-open-id',
done: false
})
.get({
success: function(res) {
// res.data 是包含以上定义的两条记录的数组
console.log(res.data)
}
})
db.collection('user').doc('todo-identifiant-aleatoire').update({
// data 传入需要局部更新的数据
data: {
// 表示将 done 字段置为 true
done: true
},
success: function(res) {
console.log(res.data)
}
})
db.collection('user').doc('todo-identifiant-aleatoire').remove({
success: function(res) {
console.log(res.data)
}
})
更多用法可以去查看微信官方文档
为了统一管理和方便调用,我们可以封装下小程序端请求云函数的方法
新建文件 scr/config/http.js
const http = function (param) {
const isHideToast = param.isHideToast || false; //是否隐藏错误提示
return new Promise((resolve, reject) => {
wx.cloud.callFunction({
// 要调用的云函数名称
name: param.moduleName || "main",
// 传递给云函数的参数
data: {
$url:param.url,
...param.data
}
}).then(res => {
if (res.result) {
if (res.result.code === 200) {
resolve(res.result.data);
} else {
if (isHideToast) {
uni.showToast({
title: res.result.data.msg || '返回失败',
duration: 1500,
icon:'none'
});
}
reject(res.result.data);
}
} else {
uni.showToast({
title: 'url不存在',
duration: 1500,
icon:'none'
});
}
})
})
}
export default http
再把http对象挂载到vue
在src/main.js
下,添加
import http from './api/http'
Vue.prototype.$http = http
在小程序端调用:
this.$http({
url: "/login",
data: {}
}).then(res => {
console.log(res)
})
原文地址:https://juejin.cn/post/6936855461895340068