微信小程序開發了雲開發的功能, 提供了數據庫、雲函數、儲存空間的服務。在此基礎上,基本能夠用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
複製代碼
最近微信關閉了更名的通道, 暫時改不了名字和頭像了...