- 蘇格團隊
- 作者:Brady
背景
最近團隊內部需要用到一個小程式,主要功能簡單概括是團隊成員之間可以相互傳送評價,並能夠檢視自己收到和發出的評價以及團隊中各成員收到的評價數量。 開發人員一開始是隻有我一個人,之前並沒有過開發小程式的經驗。於是就毅然開始了小程式開發的踩坑之路。
技術選型
技術選型包括前端框架以及服務端語言及資料庫的選型。
前端技術選型:
在前端方面,希望能夠達到的目標是:
- 工程化、元件化
- 有好用的ui庫
- 有良好的社群維護,比較少bug
- 文件健全,容易上手的
目前流行的小程式框架主要有三款,分別是WePy、mpvue、Taro。
根據上述的目標來篩選的話,基本上這三款都是符合要求的。前兩款的程式碼風格都是類似於vue,第三款是類似react的語法,並且可以將一份程式碼轉換為h5、RN、支付寶小程式等。由於本人所在公司用的技術棧主要為react,為了減少學習成本和後期換人開發維護的成本,最終選擇taro作為前端的框架。
服務端技術選型:
在服務端方面,由於我只會用nodejs和mongodb,所以選擇不多。開啟小程式的開發者瞭解到有提供雲開發的功能,那就在這兩種方案之中挑一個了。
如果使用nodejs+mongodb自己搭建服務端的話,需要自己去搭建伺服器和運維,但是使用雲開發的話,騰訊雲可以免費提供兩臺伺服器,並且小程式有提供api可以在頁面運算元據庫的資料,開發起來應該效率會很高。
考慮到需要開發的小程式並不複雜而且使用者量只是部門內的幾十個人,所以先選擇雲開發把小程式做出來再說。
雲開發體驗
雲開發帶來最大的感覺是弱化了後端和運維的概念,在前端可以直接通過api檢視資料庫,程式碼如下:
const db = wx.cloud.database()
db.collection('todos').doc('todo-identifiant-aleatoire').get({
success(res) {
// res.data 包含該記錄的資料
console.log(res.data)
}
})
複製程式碼
有了這種操作之後我開發起來就基本上沒有了調介面這種念頭了,但是這樣也會有一個問題,直接用這個api查資料的話最多隻能查詢20條,多了的話就要分頁了。如果不想分頁的話可以用雲函式,雲函式最多一次能拿100條資料。
雲函式是部署在雲端的函式,寫法如下:
const cloud = require('wx-server-sdk')
// 雲函式入口函式
exports.main = async (event, context) => ({
sum: event.a + event.b
})
複製程式碼
把上述檔案部署之後就可以直接在頁面呼叫了:
wx.cloud.callFunction({
// 雲函式名稱
name: 'add',
// 傳給雲函式的引數
data: {
a: 1,
b: 2,
},
success(res) {
console.log(res.result.sum) // 3
},
fail: console.error
})
複製程式碼
雲函式就類似於介面,可以寫一些對資料的處理邏輯,與寫介面相比好處在於少了好多校驗的邏輯,只專注於業務。
雲開發還有一個特點就是有一個JSON資料庫,和mongodb很類似,熟悉mongodb的同學都可以快速上手。
這個資料庫還有幾個特點:
- 使用者建立的資料會自動生成一個_openid屬性
- 每個集合都有許可權設定,預設是僅建立者和管理員可讀寫
- 這個資料庫沒有類似於mongo shell之類的操作命令,另外開發工具裡面又有很多bug,管理資料挺麻煩的,使用體驗不佳
配置開發和正式環境
騰訊雲開發可以免費提供兩臺伺服器,各有一個id,可以一臺用作開發環境,一臺作為正式環境。
用taro框架生成的目錄結構中有一個config資料夾,裡面放著各種環境的配置:
defineConstants: {
envId: 'brady-dev'
},
複製程式碼
然後在入口app.js處使用此變數
wx.cloud.init({
env: envId
})
複製程式碼
配置好之後執行npm run dev:weapp就是開發環境,執行npm run build:weapp後就是正式環境了
賬號系統的設計
用openid標識使用者:
在小程式裡面每個使用者都會有一個唯一的openid,我們可以用openid作為唯一標識,將使用者的openid、暱稱、頭像等資訊存在一張表裡面。
通過授權按鈕獲取使用者資訊:
openid可以通過wx的獲取openid的介面獲取,但是使用者的暱稱頭像等資訊是需要使用者授權後才能獲取的。以前獲取授權可以調api直接進來就彈出一個獲取許可權的彈窗,現在獲取授權改成需要使用者自己觸發了,所以要專門寫個button來提示使用者點選。
async await寫法
小程式獲取資料的api大多提供success和fail的回撥,而且呼叫後返回的是promise,可以比較方便地寫非同步的邏輯。不過個人覺得用async await的寫法的話程式碼會看起來接近於同步,更加直觀。
async/await是es7的語法,在小程式中直接寫會報錯。解決方法就是去facebook的generator庫 下載一個runtime.js,在使用async/await語法的地方引入該js就可以正常使用了。
const regeneratorRuntime = require("../../lib/runtime.js");
複製程式碼
抽象請求邏輯
在頁面中經常呼叫雲函式獲取查詢資料庫的api會寫出很多重複的程式碼,於是就再寫了一個adapter.js封裝這些請求,並做統一錯誤處理
const db = wx.cloud.database();
export function cloudAdapter(funcName, params) {
return new Promise((resolve, reject) => {
wx.cloud.callFunction({
name: funcName,
data: params || {},
success: res => {
resolve(res)
console.log(`[雲函式${funcName}] 呼叫成功: `, res);
},
fail: err => {
resolve(null)
console.log(`[雲函式${funcName}] 呼叫失敗: `, err);
}
})
})
}
複製程式碼
封裝過後在頁面上調雲函式時程式碼就變成下面這樣子了,比原來簡潔了很多
const result = await cloudAdapter("fetchRecords", { params });
result && dosomething(result)
複製程式碼
原本的程式碼
wx.cloud.callFunction({
name: 'add',
data: {
a: 1,
b: 2,
},
success(res) {
console.log(res.result.sum)
},
fail: console.error
})
複製程式碼
圖片的使用
在小程式中如果要使用本地圖片只能使用Image標籤,如果是css中要用到圖片的話就只能寫cdn的地址了。還好使用了雲開發,有一個雲儲存的功能。
把圖片放在圖片管理中,點選詳情會有一個下載的連結,這個連結可以用在css中。由於使用了sass,就把所有可能會複用的icon的圖片都放進了一個公共的scss檔案中,寫成變數給各頁面使用。
// variable.scss
// 圖片連結
$icon-next: 'https://xxx';
$icon-prev: 'https://xxx';
複製程式碼
元件化
taro框架讓我們可以幾乎完全按照react的方式去寫元件,因為我們可以很方便地把程式碼分割,拆出公共元件。但是由於小程式中無法支援高階元件,所以需要用到高階元件的地方我選擇了使用render props去實現。
傳送模板資訊
小程式可以傳送模板資訊給使用者,但是有一個前提,使用者一定要先使用過這個小程式。因為傳送模板訊息的介面需要用到一個formid,而這個formid必須要使用者在手機上點選了按鈕才能拿到。
目前我們的做法是寫一個公共元件,將頁面中的各種元素傳進去,返回一個包了很多層button的元素。這樣的話使用者點選頁面元素就會觸發button手機formid的事件,將使用者的formid存進資料庫裡。
每個formid只能發一條資訊,而且有效期為7天,所以我們的處理邏輯是發資訊的時候先從資料庫把該使用者的formid拿出來,找到可用的formid。發完訊息後把該使用者所有已過期和失效的formid從資料庫裡刪除。
滾動事件與rpx轉換
遇到一個頁面滾動到某個位置某個元素要吸頂的功能,需要監聽到滾動事件。在小程式中監聽滾動事件可以用onpagescroll事件或者scroll-view,但是這兩種返回來滾動的值單位都是px,是物理畫素。在不同的機型中,同一個元素滾動到頂部所滾的物理畫素是不一樣的,需要轉化成為rpx。在小程式中頁面的寬度規範定義為750rpx,所以轉換公式為
prx = 750 / screenWidth * px
複製程式碼
最後
以上即為寫這個小程式時的思考過程以及所踩的各種坑,希望對大家有幫助。