微信小程序开发了云开发的功能, 提供了数据库、云函数、储存空间的服务。在此基础上,基本能够用js一把捞一个相对完整的服务,而且省下了发布、部署、运维的繁琐。css
语言同构、js一把捞, 对前端开发很是友好, 使用js就能够完成整个业务流程。
前端
环境整合的很是好, 不用操心各类环境配置、数据库、存储空间、部署、运维的东西,减轻了开发复旦node
自带登陆和帐号体系,方便接入git
过多的回调、异步致使代码难看切难以维护、难以调试。github
云函数的框架过于简陋, 处理复杂业务的时候对代码组织能力要求很高数据库
数据库多表联查的时候很忧伤, 严重影响性能npm
没有公共代码块, 没法共享通用代码, 难以整合组织代码小程序
通过考虑决定作一个小号的微博小程序, 梳理的功能以下微信小程序
根据官方的api文档, 小程序的云函数也是能够经过http调用的,这就给一个独立的后台提供了技术接口。 咱们能够经过http调用小程序云函数来读取和操做数据库来实现产品后台的功能,是否能够经过htpps上传图片还待探索
用户端的就是一个小号的微博了。 其中,微信提供了一个存储空间,能够方便的进行文件的存储,帐号部分能够直接经过微信的鉴权机制,使用openid做为用户id。
很少说, 上设计稿。 api
其实上面的都不重要,坑都在这里
这里要分两部分说
function promisify (api) {
return (options, ...params) => {
return new Promise((resolve, reject) => {
api(Object.assign({}, options, { success: resolve, fail: reject }), ...params);
});
}
}
复制代码
// 这样就能够简化微信原生的api
const getSetting = promisify(wx.getSetting)
const res = await getSetting()
复制代码
可是async 语法也有很差的地方在于异常捕获写起来很难看, 越是复杂的逻辑, 用户捕获异常的catch就越很差处理, 这里可使用await-to-js来进一步优化
import to from 'await-to-js'
// 使用node风格的异常捕获
const [err, res] = await to(getSetting())
复制代码
require
例如 const to = require('await-to-js').default;
小程序推荐使用rpx做为尺寸单位, 切图适配的时候, 小图标可能会在缩放的时候失真,推荐使用字体图标。将制做好的字体图标放入小程序的css文件中就行了,我这里是用的阿里icon的图标库, 将base64的css样式直接放在全局的css中
微信开发工具自带了编译和没法替代的云开发工具, 目前是没有办法摆脱它了。 可是在编辑代码的时候仍是能够用其余工具的。能够用vscode做为代码编辑攻击, 安装minapp等插件。微信开发工具做为预览和调试的工具就好
在云函数中是支持直接使用npm包的, 可是每个云函数的入口对应一个文件夹, 每个文件夹须要单独npm。为了能够在本地断点调试云函数,咱们必须在云函数下的每个文件夹install一下。这操做是真的难受。。。
先放一下数据库的方案
前文说过, 云函数每个文件夹视为一个入口文件,而且须要单独install一下。 咱们最少须要4张表,最起码的增删改查就须要16个接口, 一个接口一个入口显然不可能, 因此咱们可能须要本身作一下路由的设计。
考虑到代码的复用, 我将每个入口做为一个功能块, 将代码的功能拆分红service层、router层、controller层. 在小程序调用云函数的时候传入action字符串做为路由的参数。将对数据库的操做细化,做为service便于复用。 在controller里调用service来处理复杂逻辑。
// user/user.js
// UserBase 肯定每一个集合的数据结构
class UserBase {
constructor(data) {
this.openId = data.openId
this.avatarUrl = data.avatarUrl
this.city = data.city
this.country = data.country
this.gender = data.gender
this.language = data.language
this.nickName = data.nickName
this.province = data.province
this.signature = null // 签名
this.watchList = [] // 关注列表
this.releaseList = [] // 发布列表
this.createTime = db.serverDate()
this.userStatus = 0 // 用户状态 0 正常 1 限制登陆
this.inviteUser = null
}
}
复制代码
// 这里用来实现对数据库的操做
class User {
// 获取用户信息
async getUserInfo(openId) {
const [err, {data}] = await to(db.collection('user')
.where({ openId: openId })
.get())
if (err) return Promise.reject(err.errMsg)
if (Array.isArray(data) && data.length) return data[0]
else return null
}
// 建立新用户
async createUser (userInfo) {
let [err, res] = await to(db.collection('user').add({ data: new UserBase(userInfo)}))
if (err) return Promise.reject(err.errMsg)
return res._id
}
}
复制代码
Controller能够经过继承也能够单独引入进来运行
// user/userController.js 这里调用service来处理复杂逻辑
// 根据状况也会调用其余的模块, 这个时候就用callFunction
// 云函数入口文件
const User = require('./user.js')
const cloud = require('wx-server-sdk')
cloud.init({ env: 'prod-4ygqk'})
const to = require('await-to-js').default;
class UserController extends User {
// 处理登陆
async handelLogin(event) {
const { OPENID } = event
const [err, res] = await to(this.getUserInfo(OPENID))
if (err) return {err, res}
if (res) return {err, res}
if (!event.loginInfo) {
return {err: '注册用户失败,请先调用wx.userInfo接口', res}
}
event.loginInfo.openId = OPENID
return this.handelCreateUser(event)
}
// 注册用户
async handelCreateUser(event) {
const { loginInfo, OPENID } = event
const [err, res] = await to(this.createUser(loginInfo))
if (err) return {err, res}
const [_err, _res] = await to(this.getUserInfo(OPENID))
if (_err) return {err, res: _res}
return {err, res: _res}
}
// 经过openId查询用户
async queryUserByOpenid(event) {
const { targetUser, OPENID} = event
// 若是没有传openId进来, 就查询当前用户
const seatchOpenId = targetUser || OPENID
const [err, res] = await to(this.getUserInfo(seatchOpenId))
if (err) return {err, res}
// 查询是否关注过该用户
if (res && targetUser) {
const [error,{result}] = await to(cloud.callFunction({
name: 'attention',
data: {
action: 'queryIsAttention',
currentUser: OPENID,
targetUser: targetUser
}
}))
if (error) return {err: error, res: result}
res.isAttention = result.res
}
return {
res: res,
err: null
}
}
}
module.exports = UserController
复制代码
这里咱们将openId做为用户识别码挂载在event上, 供控制器使用 在Controller须要调用其余模块的Controller时, 也将所需的参数挂载在event上。 这里的event实际上就是此次请求的上下文
// 云函数入口文件 user/index.js
const cloud = require('wx-server-sdk')
cloud.init({ env: 'prod-4ygqk'})
const UserController = require('./userController.js')
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const { OPENID, APPID } = wxContext
event.OPENID = OPENID
const user = new UserController()
const { action } = event
switch (action) {
case 'login': {
return user.handelLogin(event)
};
case 'createUser': {
return user.handelCreateUser(event)
};
case 'queryUserByOpenid': {
return user.queryUserByOpenid(event)
};
}
}
复制代码
async queryArticlebyId(event) {
const { OPENID, id } = event
// 查询对应的文章内容
let [err, res] = await to(article.queryArticlebyId(id))
// 有错误返回错误, 没有查到返回空
if (err) return {err, res}
if (!res) return {err, res}
// 查询文章用户, 调用user模块
const [error, { result }] = await to(cloud.callFunction({
name: 'user',
data: {
action: 'queryUserByOpenid',
currentUser: event.OPENID,
targetUser: res.openId
}
}))
// 调用userInfo错误
if (error) return {err: error, res}
// userInfo本身的错误
if (result.err) return {err: result.err, res: res}
res.user = result.res
// 查询用户是否已经收藏, 调用收藏模块
const [collectionErr, collectionRes] = await to(article.queryIsCollection(OPENID, id))
res.isCollection = collectionRes
return {res, err: null}
}
复制代码
async queryArticleAll(event) {
const { userInfo, size = 10, page, sort = 'desc', orderBy = 'createTime' } = event
let ArticleList = await article.queryArticleAll({ size, page, sort, orderBy })
if (ArticleList.length === 0) {
return []
}
const funList = ArticleList.map(async article => {
// 查询文章的做者
const [err,{result}] = await to(cloud.callFunction({
name: 'userInfo',
data: {
action: 'queryUserByOpenid',
currentUser: event.OPENID,
targetUser: article.openId
}
}))
let user = result.res || null
article.user = user
return article
})
return {res: await Promise.all(funList), err: null}
}
复制代码
其余就没有啥子东西可写了。后面使用http调用云函数的之后再继续尝试。 在调试云函数的时候几乎花掉了所有的耐心....最后贴代码和地址
https://github.com/xanggang/picture-miniapp
复制代码
最近微信关闭了更名的通道, 暂时改不了名字和头像了...