寫在前面
微信小程序出來也蠻久了,經(jīng)過了市場的考驗,已經(jīng)站穩(wěn)腳跟,融入到了各行各業(yè),市場需求激增打來的是開發(fā)人員的緊俏,現(xiàn)在已經(jīng)各大招聘網(wǎng)站也能看到有小程序開發(fā)的崗位在提供。恰逢公司有業(yè)務(wù)需要,現(xiàn)在入坑小程序開發(fā),以一個初學(xué)者的身份把這一過程進行記錄并分享,希望能在和朋友們的交流中提升自我。
其實但凡有一丟丟的編程基礎(chǔ),想入門都是很簡單的事情,只要能跟著 官方文檔 把流程走一遍,就算入門了。現(xiàn)在不比早期,官方文檔被吐槽寫的跟 shi 一樣,所以還==非常推薦大家仔細讀一下官方文檔==。經(jīng)常在交流的時候,看到有人連官方文檔上寫的清清楚楚的東西都拿來問,這是很可悲的事情。
有些問題官方文檔上查不到,可以在官方 開發(fā)者社區(qū) 上輸入關(guān)鍵字查一下,基本上前期遇到的問題都能得到解決。這兩個地方都不能解決困惑的話,再去交流群求問或查看第三方論壇,如 很快-微信開發(fā)平臺 。甚至說有的同學(xué)喜歡看視頻,網(wǎng)上也能找到。當(dāng)然也建議大家?guī)е鴮嵺`結(jié)論和個人理解去交流,這樣容易得到答案,個人成長也會很快。
一、開發(fā)準備
不同于以往的項目,開發(fā)人員寫完代碼就可以了,在小程序開發(fā),尤其是個人項目中,開發(fā)人員需要兼顧開發(fā)、運維、推廣、客服等多個任務(wù),雖然這一切都有微信提供的管理后臺,但還是需要開發(fā)人員進行相關(guān)配置來保障項目的運行。
1. 小程序注冊
可以把小程序理解為在微信大市場上注冊的小商家,那么每個小程序就需要在 微信公眾平臺 注冊賬號用于管理。這個賬號可以提供給我們小程序的唯一標示 AppId ,也可以幫助我們對小程序進行管理,協(xié)助我們完成編碼開發(fā)以外的事情。注冊方式主要兩種:
1.1 官網(wǎng)注冊
立即注冊 -> 小程序
1.2 已有公眾號后臺(不支持個人類型公眾號)
小程序 -> 小程序管理 -> 快速注冊并認證小程序
補充:
- 注冊賬號要注意賬號類型,選擇小程序
- 小程序暫不支持更換主體(個人/企業(yè)),注冊時類型不要選錯
? ? - 個人類型小程序不支持不部分權(quán)限:如,微信用戶手機號、微信支付、微信卡券等
- 同一郵箱不能注冊多個公眾平臺賬號,同一微信賬號可以登錄多個公眾平臺賬號
? ? - 多人管理開發(fā),均使用同一賬號登錄,微信掃碼確認登錄;其他人(非管理員)的微信賬號可以通過配置 用戶身份-登錄權(quán)限 來擁有該能力
- 企業(yè)需要進行主體信息認證,周期較長,有 300 塊費用,通過了還不能更改,所以要慎重填寫
- 綁定開發(fā)者,并給與不同的權(quán)限
2. 開發(fā)工具
基本使用簡單,畢竟中文版,下載了看著引導(dǎo)創(chuàng)建一個 QuickStart? 新項目,就能開擼了。或者下載這個 演示源碼,當(dāng)項目跑一下。整個開發(fā)工具還是挺清爽的,有種小霸王 N 合一的感覺。其中模擬器、編輯器、調(diào)試器都很直觀,可以通過左上角按鈕進行顯隱操作,使用上搞過前端開發(fā)的都比較熟悉,此處不再贅述。說一下幾個常用功能鍵:
2.1 預(yù)覽、遠程調(diào)試
兩種真機調(diào)試的方案,各有不同的適用場景和注意事項:
- 預(yù)覽
? ? - 需要擁有開發(fā)者權(quán)限的微信賬號掃描才能使用,常用于他人在未發(fā)版情況下體驗最新代碼
? ? - 只有IDE登錄微信賬號掃描時,才和IDE共用一套緩存(此時IDE清緩存可以影響到真機)
? ? - 可以開啟調(diào)試模式(微信右上角菜單 -> 打開調(diào)試),通過 vConsole 按鈕展示真機調(diào)試區(qū)
? ? - 看不到請求具體信息,只能通過控制臺打印
- 遠程調(diào)試
? ? - 可以在PC上看到真機的控制窗口,常用于配合測試人員復(fù)現(xiàn)問題
? ? - 獨立于IDE緩存,即賬號A登錄成功遠程調(diào)試后,賬號B進入遠程調(diào)試,看到的是賬號A的信息
? ? - 此時清緩存不能使用IDE清緩存,只能在遠程調(diào)試窗口執(zhí)行 wx.clearStore() 這種方式
? ? - 也沒有 network
2.2 清緩存
開發(fā)和測試中需要經(jīng)常模擬登錄、授權(quán)的不同處理結(jié)果,此時就需要用到清緩存功能。IDE 提供了以下功能,可以一次全清也可以清除某一項,對應(yīng)真機調(diào)試的實現(xiàn)如下:
- 清除代碼緩存
? ? - 相當(dāng)于真機調(diào)試時 - 刪除小程序重新加載代碼
- 清除授權(quán)緩存
? ? - 相當(dāng)于真機調(diào)試時 - 微信右上角菜單 -> 關(guān)于xxx -> 右上角菜單 -> 設(shè)置?
- 清除數(shù)據(jù)緩存
? ? - 相當(dāng)于真機調(diào)試時 - vConsole -> Wechat -> 點擊wx.clearStorage()
- 清除網(wǎng)絡(luò)緩存
? ? - 真機調(diào)試的網(wǎng)絡(luò)緩存暫不清楚如何清除,靜態(tài)資源通過增加時間戳
? ? ? ? - 注意同一個時間戳對應(yīng)同一份資源緩存
? ? ? ? - Date.parse(new Date()).toString().slice(0, 8) 固定間隔 100s
? ? ? ? - Date.parse(new Date()) / (space * 60 * 1000)? 根據(jù) space 設(shè)置間隔分
- 清除登錄緩存
? ? - 由于是靜默登錄,一般忽視該緩存
2.3 上傳
開發(fā)完成后,小程序發(fā)布前,需要將代碼上傳到微信的服務(wù)器。關(guān)于上傳有以下需要注意:
- 每個擁有開發(fā)權(quán)限的賬號都可以上傳,每個賬號上傳的代碼是分開的
- 每個人只能保持一份上傳的代碼,二次上傳會進行覆蓋
- 微信公眾平臺 / 開發(fā)管理
? ? - 線上版本
? ? - 審核版本
? ? ? ? - 展示審核中和審核通過但未發(fā)布的版本
? ? ? ? - 同時只有一個版本進行展示
? ? ? ? - 首次審核周期較長,需要3-5個工作日,此后審核較快
? ? ? ? - 首次審核較為嚴格,需要注意很多問題,如誘導(dǎo)分享,詳見[常見拒絕情形](https://developers.weixin.qq.com/miniprogram/product/reject.html#36-UI-%E8%A7%84%E8%8C%83)
? ? - 開發(fā)版本
? ? ? ? - 每個版本都可以設(shè)為體驗版本,但同時只有一個體驗版本,通過二維碼供擁有體驗者權(quán)限的人進行測試
? ? ? ? - 每個版本都可以提交審核,但同時只有一個審核中版本
? ? ? ? - 每個賬號維護一份開發(fā)版本
2.4 詳情(IDE右上角)
- 項目設(shè)置
? ? - 可以選擇調(diào)試基礎(chǔ)庫,來測試兼容問題(存在兼容問題的 api 都寫了最低版本,也可以查看 [歷史更新日志](https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/uplog.html) 進行了解)
? ? - 未設(shè)置合法域名時,可以勾選 不校驗安全域名 選項(線上域名一定要 TLS/SSL 認證)
- 域名信息
? ? - 查看合法域名
二、開發(fā)優(yōu)化
1. promisify
https://github.com/stefanpenner/es6-promise
由于小程序提供的 API 都是回調(diào)風(fēng)格的,在習(xí)慣了 ES6 promise 風(fēng)格后,對回調(diào)嵌套不是很感冒,所以考慮進行包裝處理。此處小程序提供的 Promise 有兼容問題,所以使用了 es6-promise 包來進行包裝。
```
/**
* 將小程序的API封裝成支持Promise的API
* @params fn {Function} 小程序原始API,如wx.login
*/
function wxPromisify(fn) {
? return (obj = {}, cb) => {
? ? return new Promise((resolve, reject) => {
? ? ? obj.success = (res) => {
? ? ? ? resolve(res);
? ? ? };
? ? ? obj.fail = (res) => {
? ? ? ? reject(res);
? ? ? };
? ? ? let taskObj = fn(obj);
? ? ? cb && (typeof cb == 'function') && cb(taskObj);
? ? })
? }
}
```
討論:如何拿到原生 api 的返回值?
promise 給了我們在 success 回調(diào)中使用 return 關(guān)鍵字的能力,但沒有 api 執(zhí)行后的 return 失去了。此處使用 callback 拋出返回值,但是感覺并不優(yōu)雅,有更好處理方式的請指點下我。
2. request
小程序提供的原生接口是 wx.request ,出于以下幾點考慮,對其進行二次封裝:
1. 小程序沒有 cookie ,需要在 heaser 中攜帶 sessionId
2. 原生寫法是回調(diào)風(fēng)格,改造成 promise 風(fēng)格
3. 需要公用部分業(yè)務(wù)相關(guān)的數(shù)據(jù)處理
4. 需要對請求進行統(tǒng)一攔截處理,如 loading 、timeout
3. 按鈕節(jié)流閥
經(jīng)常這種需求,按鈕不能連續(xù)點擊,所以提供一個節(jié)流功能的工具:
<pre>
function btnThrottle(self){
? selt.setData({
? ? buttonClicked: true?
? });
? setTimeout(() => {
? ? self.setData({
? ? ? buttonClicked: false
? ? })
? }, 500)
}
creat: function() {
? if(this.data.buttonClicked) return;
? util.btnThrottle(this);
}
</pre>
4. 代碼清緩存
有時候在調(diào)試的時候需要經(jīng)常保持代碼最新,經(jīng)常執(zhí)行刪除小程序還是很麻煩的,可以考慮使用下面方法:
```
onHide: function() {
? wx.setEnableDebug({
? ? enableDebug: true,
? ? success: () => {
? ? ? wx.setEnableDebug({
? ? ? ? enableDebug: false
? ? ? })
? ? }
? })
}
```
- 優(yōu)點:可以清除代碼緩存,每次打開都是重新加載
- 缺點:沒辦法保持退出時的狀態(tài),所以暫不考慮用到生產(chǎn)環(huán)境
三、常見問題
1. 登錄邏輯
官方建議自己保存用戶登錄狀態(tài),不要頻繁調(diào)用 wx.login ,否則會被限制登錄。
有兩種思路:
1. 先檢查登錄是否過期(wx.checSsession),在未過期的基礎(chǔ)上執(zhí)行其他請求(不是所有請求都需要登錄,如世界排行)
2. 所有 api 請求都執(zhí)行判斷,如果返回未登錄錯誤碼(getUserInfo:fail auth deny),則申請授權(quán)(wx.authorize),授權(quán)成功繼續(xù)請求,授權(quán)拒絕則強跳授權(quán)頁(wx.openSetting)
目前登錄判斷:
1. wx.checkSession、wx.getStorage 檢查登錄是否過期和 sessionId 是否存在
2. 成功則判斷結(jié)束,否則 wx.login、wx.getUserInfo 拿到用戶信息
3. 成功則用拿到的信息向后臺登錄生成 sessionId,失敗則申請授權(quán)操作(允許授權(quán)會繼續(xù),失敗授權(quán)強跳授權(quán)頁)
4. 成功拿到 sessionId 則保存 storage,失敗提示網(wǎng)絡(luò)問題
[最優(yōu)體驗:](https://mp.weixin.qq.com/s/JBdC-G9MwaptFjQeD9ujeA)
1. 調(diào)用 wx.login 獲取 code,然后從微信后端換取到 session_key,用于解密 getUserInfo返回的敏感數(shù)據(jù)。
2. 使用 wx.getSetting 獲取用戶的授權(quán)情況
? ? - 如果用戶已經(jīng)授權(quán),直接調(diào)用 API wx.getUserInfo 獲取用戶最新的信息;
? ? - 用戶未授權(quán),在界面中顯示一個按鈕提示用戶登入,當(dāng)用戶點擊并授權(quán)后就獲取到用戶的最新信息。
3. 獲取到用戶數(shù)據(jù)后可以進行展示或者發(fā)送給自己的后端
2. 路由跳轉(zhuǎn)相關(guān)
系統(tǒng) api 和 navigator 組件支持新開、重定向、返回、tab切換、重啟動五種方式。讀懂路由出入棧規(guī)則,可以幫你較好的處理跳轉(zhuǎn)問題。但歸根結(jié)底我們還是應(yīng)該避免過于復(fù)雜的跳轉(zhuǎn)邏輯,防止分享進入時的路由跳轉(zhuǎn)問題。
有一種情況需要格外注意,在實現(xiàn)后退功能的時候,可能已經(jīng)沒有辦法后退了(如分享卡片進入或已經(jīng)退出當(dāng)前頁面但代碼還在執(zhí)行),此時執(zhí)行 wx.navigateBack 會閃退。
```
// 兼容處理不同打開方式的后退
function toHome() {
? let pageCount = getCurrentPages().length;
? if(pageCount > 1) {
? ? wx.navigateBack({
? ? ? delta: 1
? ? })
? } else {
? ? wx.redirectTo({
? ? ? url: '/pages/home/index'
? ? })
? }
}
```
需要注意的是 tab 切換時的路由出入棧規(guī)則:
- tab a 到 tab b 相互切換時,觸發(fā)的是 onHide 和 onShow(第一次切換會有 onLoad)
- tab a 的子頁面切到 tab b 時,會把所有 a 的子頁面 onUnload
3. 數(shù)據(jù)共享的實現(xiàn)
1. url傳值 - 基于頁面 - 適合少量值傳遞
```
wx.navigateTo({
? url: '/page/home/index?id=' + id
})
onload: function(opt) {
? console.log(opt.query)
}
```
2. storage - 基于本地緩存 - 適合大量值傳遞
注:
- 同一個微信用戶,同一個小程序 storage 上限為 10MB
- localStorage 以用戶維度隔離,同一臺設(shè)備上,A 用戶無法讀取到 B 用戶的數(shù)據(jù)
- 不建議將關(guān)鍵信息全部存在 localStorage,以防用戶換設(shè)備的情況
[官方文檔-api-數(shù)據(jù)緩存](https://mp.weixin.qq.com/debug/wxadoc/dev/api/data.html)
3. 全局 App - 基于內(nèi)存
```
getApp().globalData.xxx
```
4. 退出當(dāng)前頁面后,代碼還在執(zhí)行
由于用戶退出頁面的操作具有不可控性,所以隨時都可能出現(xiàn)代碼不在當(dāng)前頁面執(zhí)行的情況,而這種情況并不是我們想要看到的。所以需要對這種情況進行處理,保證代碼執(zhí)行穩(wěn)定可控。常見的有異步請求、定時器。所以最基本的要求就是在退出頁面是執(zhí)行以下操作:
```
onUnload: function () {
? ? // 中斷請求
? ? if (wx.canIUse('requestTask.abort')) {
? ? ? this.abortInit && this.abortInit.abort();
? ? }
? ? // 清理定時器
? ? clearInterval(this.xxxTimer);
? ? // 重置數(shù)據(jù)
? ? self.setData({
? ? ? ? //...
? ? });
? },
```
但總有漏網(wǎng)之魚,在開發(fā)中我就遇到過,請求中斷了,定時器清理了以后還在執(zhí)行的情況。出現(xiàn)這種情況第一感覺并沒有清理成功,API 執(zhí)行出現(xiàn)了問題。
后來測試多次發(fā)現(xiàn),并非 API 的鍋,而是因為在未能中斷的異步操作中觸發(fā)了新的異步操作,而新的異步操作已經(jīng)無法控制中斷。如:某個 request 請求沒能 abort 中斷,該操作的回調(diào)中又調(diào)起了另一個 request 或 setTimeout ,此時場面失控了。
所以,流程清晰可控是必須的,各位在處理業(yè)務(wù)邏輯的時候一定要注意此類問題的出現(xiàn)。
5. share
作為非常重要的一個推廣途徑,用戶分享自然是個很重要的功能點,小程序提供了相關(guān)的 API ,在使用中遇到以下問題并記錄:
1. 分享最終執(zhí)行的是 onShareAppMessage 對應(yīng)的函數(shù),相關(guān)的邏輯在其中處理
2. 分享的參數(shù) imageUrl 存在低版本兼容問題,設(shè)置為 null 不能實現(xiàn)默認截屏, '' 可以截屏
3. 分享可以攜帶參數(shù),寫在 path 參數(shù)中即可,同 url 中的 query
? ? - 如果需要獲取該參數(shù),可以在 onShow 的參數(shù) options 中獲取到
4. 場景需要:分享到群判斷,并判斷是否群分享進入
? ? - 先設(shè)置帶 shareTicket 的轉(zhuǎn)發(fā)
? ? ? ? ```
? ? ? ? wx.showShareMenu({
? ? ? ? ? ? withShareTicket: true
? ? ? ? });
? ? ? ? ```
? ? - 在分享的成功回調(diào)函數(shù)中判斷 shareTickets 群標識,存在即為分享到群
? ? - 獲取場景值(onShow 的參數(shù) options 中 scene),判斷進入方式,常用場景值:
? ? ? ? - 1007:單人對話小程序卡片
? ? ? ? - 1036:App 分享消息卡片
? ? ? ? - 1044:群分享小程序卡片
6. 自定義分析
產(chǎn)品的良性發(fā)展自然少不了運營進行數(shù)據(jù)分析,常規(guī)做法是進行埋點統(tǒng)計。而小程序已經(jīng)提供給用戶一套相對來說比較完善的數(shù)據(jù)分析功能,可以登錄微信公眾平臺 -> 數(shù)據(jù)分析查看,也可以通過小程序助手(官方小程序)便捷查看,當(dāng)前前提是需要賬號擁有數(shù)據(jù)分析的權(quán)限。
雖然官方提供的數(shù)據(jù)分析已經(jīng)滿足大部分需求,但是實際生產(chǎn)中肯定還需要定制數(shù)據(jù)分析,這里也有提供自定義分析。實現(xiàn)起來就是,先在微信公眾平臺進行自定義分析的事件注冊,如果選擇 API 上報則還是需要進行埋點配合。以下對自定義分析作簡要說明:
1. 最低版本
? - 自定義數(shù)據(jù)上報僅對微信6.5.4及以上版本生效,涉及時間為 2017-01-23 以后更新即可
2. 新建事件
? - 事件名稱
? ? - 英文名稱:用于 API 上報
? ? - 中文名稱:用戶管理后臺
? - 配置信息
? ? - 動作觸發(fā)
? ? ? - trigger
? ? ? ? - click
? ? ? ? - 生命周期
? ? ? ? - share
? ? ? ? - switchTab
? ? ? - action
? ? ? ? - 一次性
? ? ? ? - 分步驟
? ? ? - page
? ? ? ? - app 層面的不用設(shè)置,默認 ANY_PAGE
? ? ? - element
? ? ? ? - click 需要觸發(fā)元素,類或id選擇器
? ? ? - data
? ? ? ? - 收集數(shù)據(jù)源,有默認字段和自定義字段
? ? ? ? - 自定義字段
? ? ? ? ? - 默認是從 page 實例的 data 中獲取,字段名用于統(tǒng)計顯示,字段值是指 data 中的 key
? ? ? ? ? - 也可以選擇其他數(shù)據(jù),看文檔(渲染出來的list 、 wxml中的data-、 app實例的數(shù)據(jù)、系統(tǒng)屬性)
? ? - API上報
? ? ? - 字段信息可以不填
? ? ? - 可自動生成代碼
? ? - 二者的選擇
? ? ? - 根據(jù)實際情況來,有時候點擊滿足不了要求
3. 測試事件
? - 保存并測試
? - 連續(xù)測試有時候測不到數(shù)據(jù),不要擔(dān)心,退出公眾平臺賬號重新登錄再測
4. 發(fā)布事件
? - 保存并發(fā)布
7. 微信服務(wù)通知
場景需求:開發(fā)者希望主動發(fā)送信息給用戶
說明:該功能不建議頻繁發(fā)送信息,可能會被用戶主動拒收,而且該功能需要用戶本人在微信體系內(nèi)與頁面有交互行為后觸發(fā)(主動觸發(fā))
重點:獲取用戶的 formid
實現(xiàn):
1. 必須通過 form 組件提交才能獲取 formid
2. form 組件設(shè)置 report-submit='true'
3. form 組件添加 bindsubmit 事件, event.detail = {value: {'name': 'value'}, formId: ''}
4. 必須用戶手動觸發(fā)提交表單,不能 js 模擬提交,即必須有按鈕
8. 小程序互相跳轉(zhuǎn)
- 基礎(chǔ)庫 1.3.0 開始支持,低版本需做兼容處理
- iOS 微信客戶端 6.5.9 版本開始支持,Android 客戶端即將在 6.5.10 版本開始支持,請先使用 iOS 客戶端進行調(diào)試
注:需要關(guān)聯(lián)同一公眾號
寫在最后
以上內(nèi)容并不能幫助大家熟練完成小程序開發(fā),只是簡單入門、踩坑記錄、常見業(yè)務(wù)場景處理,還有非常多自己還沒踩到的東西,如自定義組件、插件、分包加載都還沒使用,API 也只用了有限的幾個,比較重要的 微信支付 也未使用,后面用到了再一一記錄。寫出來方便大家快速接入小程序,也是自己的學(xué)習(xí)總結(jié),有描述錯誤或不完善的地方,還請大家能夠和我聯(lián)系,相互學(xué)習(xí)交流。
問個問題:為啥我的代碼片段展示出來和別人的不一樣呢?```沒用錯啊