怎么制作唱吧小程序,類似唱吧的小程序開發(fā)文檔
唱吧小程序開發(fā)上線還不到一個月的時間,唱吧小程序通過借助小程序的用完即走特性,使小程序用戶數(shù)突破200萬,下面就以最近接觸到的一款小程序為例,簡單總結(jié)一下小程序底層框架和一些api接口方面的設(shè)計思路。
1小程序框架淺析
大家都說小程序體驗好,即開即用,和普通Webview渲染的H5相比頁面啟動速度、流暢度等方面好很多,這個問題我認為需要從幾個方面考慮,首先,拋開產(chǎn)品業(yè)務(wù)層面的設(shè)計和優(yōu)化,就是小程序底層框架的設(shè)計和實現(xiàn)方面的特點。
當我們新建或打開一個小程序項目(以唱吧比賽小程序為例),即可看到如下圖的項目結(jié)構(gòu)。
小程序入口文件為app.js, 全局樣式文件為app.wxss,全局配置文件為app.json, 每個頁面中再分視圖wxml,wxss和邏輯js、文件配置json等,從這里我們可以看出,整個小程序的上層框架,也就是大體分為視圖層和邏輯層兩個部分。 (摘自官方文檔https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html)
小程序采用的MINA框架,View層主要用來渲染頁面結(jié)構(gòu),App Service層用來邏輯處理、數(shù)據(jù)請求、接口調(diào)用,它們在兩個線程里運行,整個小程序是只有一個App Service的,并且整個小程序的生命周期內(nèi)它是常駐內(nèi)存的。View層主要使用WebView渲染,而App Service邏輯層是使用JSCore運行。
通信方面,View和AppService是雙線程通信的,主要通過系統(tǒng)層的JSBridage進行通信,AppService把數(shù)據(jù)變化通知到View,表現(xiàn)方法也就是setData方法,觸發(fā)View頁面更新,View把觸發(fā)的事件通知到AppService進行業(yè)務(wù)處理。
這里要說的是,小程序是沒有DOM結(jié)構(gòu)的,那么視圖層的渲染是如何做到的呢,就是運行環(huán)境中會把pages中的WXML的節(jié)點樹結(jié)構(gòu),轉(zhuǎn)化為JS的對象,進行渲染,這也是小程序體驗優(yōu)于普通分享頁面的一大原因,省去了很多關(guān)于瀏覽器DOM的操作,由JS運行環(huán)境之間進行渲染解析。
2唱吧小程序底層搭建
那么話說回來,基于良好的框架,這次在搭建唱吧小程序底層的時候,我們其實做了哪些事情呢。
首先,我們并沒有進行純Native層的搭建和改造,而是對上述提到的API層的一次的封裝,尤其是在關(guān)于網(wǎng)絡(luò)請求的改造和小程序啟動的登錄流程方面,我們前端團隊嘗試去做一些分層和優(yōu)化。
-
網(wǎng)絡(luò)請求方面
首先網(wǎng)絡(luò)請求優(yōu)化方面,微信提供的請求接口基本長這樣:
-
wx.request({
-
url: 'test.php', //僅為示例,并非真實的接口地址
-
data: {
-
x: '' ,
-
y: ''
-
},
-
header: {
-
'content-type': 'application/json' // 默認值
-
},
-
success: function(res) {
-
console.log(res.data)
-
}
-
})
是不是感覺和之前的某種請求模式很像,沒錯,就是古老的$.ajax,這時候我們又想起了ajax的回調(diào)地獄,如果頁面的請求很多,請求的順序還有限定,瞬間又是各種嵌套,可以說是要從請求到懵逼了。
所以為了解決回調(diào)地獄和同時優(yōu)化請求代碼邏輯,我們在封裝wx.request的同時,我們在小程序開發(fā)中,引入了async/await語法糖,用到了來自facebook的regenerator模塊(詳情請戳:https://github.com/facebook/regenerator),async、await函數(shù)經(jīng)babel編譯后,再用regenerator-runtime模塊用于提供功能實現(xiàn),這一方面也得力于小程序支持ES6語法的編譯。
實現(xiàn)過程中,單獨用一個公共方法封裝,返回wx.request的promise
-
//wechat.js
-
-
const request = (url,options) => {
-
return new Promise((resolve, reject) => {
-
wx.request({
-
url: url,
-
method: options.method,
-
data: Object.assign({}, options.data),
-
header: options.header,
-
success: resolve,
-
fail: reject
-
})
-
})
-
}
之后在我們的上層公共庫中,編寫與請求相關(guān)的處理邏輯。
-
// changba.js
-
-
const regeneratorRuntime = require('./regenerator-runtime.js')
-
const wechat = require('./wechat')
-
const URI = 'xxx'
-
-
const requestAPI = async (url,opt) => {
-
const app = getApp()
-
let options = Object.assign({data: {}},opt)
-
if (/^\/api\/(.+)$/.test(url)) {
-
url = URI + url;
-
}
-
if (!options.method) {
-
options.method = 'POST';
-
}
-
let header = {
-
'Content-Type': 'application/x-www-form-urlencoded'
-
}
-
options.header = options.header || header ;
-
//除了login方法 其余接口都要加入sessionInfo也就是后端加密過的session_key
-
if (!url.includes('/checkCode')) {
-
options.data['sessionInfo'] = app.globalData.sessionkey;
-
}
-
let isTimeout = false;
-
try {
-
const ree = await wechat.checkSession();
-
} catch (error) {
-
isTimeout = true;
-
};
-
try {
-
if (isTimeout) {
-
let aaa = await login(app);
-
}
-
wx.showLoading({
-
title: '加載中'
-
});
-
const res = await wechat.request(url,options)
-
if (res && res.statusCode) {
-
if (res.statusCode != 200) {
-
if (wx.hideLoading) {
-
wx.hideLoading()
-
}
-
wx.showModal({
-
content: wechat.errMsg(res.statusCode).message || '請求失敗,請重新嘗試',
-
title: '提示',
-
showCancel: false
-
})
-
} else {
-
if (res.data && res.data.code === 1) {
-
if (wx.hideLoading) {
-
wx.hideLoading()
-
}
-
return res.data
-
} else {
-
// xxx 其他情況業(yè)務(wù)邏輯處理
-
}
-
}
-
}
-
} catch (error) {
-
console.log('請求異常信息:' + error)
-
if (wx.hideLoading) {
-
wx.hideLoading()
-
}
-
wx.showModal({
-
content: '請求信息異常',
-
title: '',
-
showCancel: false
-
})
-
}
-
}
上述封裝過程中,所以除了考慮到請求超時、檢查用戶身份等操作,還可以加入session過期等相關(guān)其他的業(yè)務(wù)處理邏輯,這也是自己搭建請求的好處,針對自己的業(yè)務(wù)需求,進行匹配和改造。
然而在經(jīng)歷這樣兩層封裝之后,在寫業(yè)務(wù)邏輯代碼的過程中,就可以一目了然的發(fā)送請求了,達到邏輯清晰且書寫自如,如果習慣了fetch以及axios的朋友應(yīng)該都會比較喜歡這種方式。
-
async getdata() {
-
let self = this;
-
let cb_getdata = await app.changba.requestAPI('/api/xxx', { data: { id: self.data.id } });
-
if (cb_getdata && cb_getdata.code === 1) {
-
// xxx
-
}
-
}
-
登錄流程方面
下面說下,啟動小程序后的登錄流程方面,在這一方面,小程序與其他不同的是,沒有固定的登錄啟動頁面,而是完全后臺交互,當然根據(jù)產(chǎn)品定位和需求,也可以自己做一套登錄系統(tǒng)~