微信小程式開發總結(附原始碼)

是呀呀呀發表於2019-02-20

最近公司專案不是很忙,有時間研究研究微信小程式。參考了目前市場上各類答題類的app、小程式等等,做了一款自己的微信答題小程式,包括前端和後端,後端是用node做的。現在已經上線了,名字叫【你問我猜猜猜】,大家感興趣的話可以去試玩一下。

會vue、react, 微信小程式,so easy

如果之前用過vue或者react,直接看看文件上手微信小程式完全沒問題。整體開發思路很相似,包括其中的一些語法,基本上都是一樣的。或者用美團的mpvue框架,那就根本不用學習小程式的語法了,寫起來跟vue一樣。但是我們開發的時候沒有用框架,用的是原生的微信小程式語言,開發起來也很easy。而且微信小程式有很多自己的API,比如圖片上傳、下載、音訊等等,專案中用到的時候再找文件就來得及。

這次開發的難點,也是微信小程式的難點,應該就是在登入了。如果把登入流程弄明白了,在開發其他的功能,基本上就是時間的問題了。

難點:微信小程式登入

看了好多文件關於登入相關的介紹,下圖的介紹是比較詳細的過程,開發過程中也是採用的這個邏輯。只不過我們沒有獲取使用者的敏感資訊,所以沒有7、8步驟。直接通過wx.getUserInfo()獲取到使用者名稱、頭像等資訊即可滿足我們的需求。

登入步驟

  1. 通過呼叫wx.login() API,成功後會拿到使用者的code資訊
  2. 將code資訊通過介面,傳給自己的後臺(不是微信的後臺),在服務端發起對微信後臺的請求,成功後拿到使用者登入態資訊,包括openid、session_key等。也就是通常所說的拿code換openid,這個openid是使用者的唯一標識。
  3. 自己的後臺,拿到openid、session_key等資訊後,通過第三方加密,生成自己的session資訊,返回給前端。
  4. 前端拿到第三方加密後的session後,通過wx.setStorage()儲存在本地,以後的請求都需要攜帶這個經過第三方加密的session資訊。
  5. 之後如果需要使用者重新登入,先去檢查本地的session資訊,如果存在,再用wx.checkSession()檢查是否在微信的伺服器端過期。如果本地不存在或者已過期,則重新從步驟1開始走登入流程。

登入的程式碼如下:

 wx.getStorage({
      key: "code",
      success: res => {
        wx.checkSession({
          success: res => {
            console.log("Session未過期,登陸狀態未失效");
          },
          fail: err => {
            // 重新登入
            console.log("Session過期,重新登入");
            loginAction();
          }
        });
      },
      fail: res => {
        console.log("無code資訊,呼叫登入介面獲取code");
        loginAction();
      }
    });
複製程式碼

登入的流程圖如下:

微信小程式開發總結(附原始碼)

注意事項

1. npm這麼容易,install個包用用?

微信小程式沒有包管理這一說(但是最新版本的好像支援npm了),所以想要用到別的庫裡的元件,只能找到原始碼,copy過來。

2. 既然openid是唯一的,那我為什麼不能用openid作為憑證,還要麻煩的用個第三方session

有可能造成資料越權。比如今天我通過我的手機登入了微信,開啟了小程式。但是明天有個朋友想用我的手機登一下微信。如果用openid作為登入憑證,登入小程式的時候檢測到openid已經存在,所以不會再走登入過程,這樣我的資料就讓我的朋友看到了。所以還是要按照官方推薦的步驟來。

3. 本地啟服務,如何通過localhost訪問服務端介面?

微信小程式預設都是https請求,如果本地開發聯調,需要在開發者工具 -> 專案設定裡,勾選上【不校驗合法域名、web-view(業務域名)、TLS 版本以及 HTTPS 證書】,這樣就可以愉快的使用localhost訪問服務端了。

4. textarea元件如何清空

一個常用的使用場景,使用者反饋裡,使用者巴拉巴拉吐槽完,點選確認傳送成功後,為了防止使用者再次重複提交,需要將textarea中的資料清空。

用過vue的大家都知道,繫結一個欄位,當成功後將這個欄位賦值為空就好了。but,微信小程式可不幹。 微信小程式文件中這樣說明:不建議在多行文字上對使用者的輸入進行修改,所以 textarea 的 bindinput 處理函式並不會將返回值反映到 textarea 上。

如何解決呢。可以給textarea繫結一個value值。用form表單去提交。成功後將value繫結的值清空就可以了。

具體程式碼如下:

<form bindsubmit="bindSubmit">
    <textarea placeholder="如果您對我們有任何建議或意見,請在此處向我們提交,期待您的寶貴建議。" name="feedbackContent" value="{{feedbackContent}}" bindinput="bindTextAreaInput" />
    <button class="submit-btn" form-type="submit" disabled="{{feedbackContent.length == 0 || btnLoading}}" loading="{{btnLoading}}" value="{{feedbackContent}}">
        提交
    </button>
</form>

bindTextAreaInput: function(e) {
    this.setData({
      feedbackContent: e.detail.value
    });
},

bindSubmit: function(e) {
    this.setData({
      btnLoading: true
    });
    addFeedbackRequest({
      content: e.detail.value.feedbackContent.trim()
    }).then(res => {
      if (res.success) {
        this.setData({
          btnLoading: false,
          feedbackContent: ""
        });
        this.showToast("提交成功,感謝您的反饋");
      } else {
        console.log("fail");
        this.showToast("提交失敗,請稍後再試");
      }
    });
  },
複製程式碼

5. 有關圖片的引用問題

給頁面新增背景是,如果通過background屬性來新增,抱歉,那你不能引用本地的圖片,只能引用經過base64轉碼的或者網上的圖片。 小程式的文件上有說,本地資源是無法通過css獲取的。但是通過image的src屬性引用的圖片,則沒有這個限制。

6. navigateTo層級不能超過5級

文件上說明:為了不讓使用者在使用小程式時造成困擾,我們規定頁面路徑只能是五層,請儘量避免多層級的互動方式。 使用wx.navigateTo()的時候,規定層級不能超過5級。如果超過5級,頁面就出錯了。但wx.redirectTo()則無此限制。 注意: wx.navigateTo()是保留當前頁面,跳轉到應用內的某個頁面,使用 wx.navigateBack 可以返回到原頁面 wx.redirectTo()是關閉當前頁面,跳轉到應用內的某個頁面。

7. 統一封裝請求,在header中攜帶session資訊

wx.request()是傳送請求的api,如果每個request請求都在header中重新一份session資訊,一定很麻煩。所以基本上前端都會封裝一個新的請求函式,包括攜帶session資訊,處理錯誤介面等功能。具體程式碼如下:

const httpRequest = data => {
    return new Promise(function(resolve, reject) {
        console.log("http request", data.url);
        let code = "";
        wx.getStorage({
            key: "code",
            success: res => {
                code = res.data;
                console.log("http request success", code);
                //發起網路請求
                wx.request({
                    url: data.url,
                    data: { ...data.data },
                    method: data.method,
                    header: {
                        code: code,
                        "content-type": "application/x-www-form-urlencoded"
                    },
                    success: function(res) {
                        if (res.data.success) {
                            resolve(res.data);
                        } else {
                            // console.log(JSON.stringify(res));
                            if (res.data.errorCode == 100) {
                                goBackIndex();
                            }
                            reject(res.data);
                        }
                    },
                    fail: function(res) {
                        console.log(JSON.stringify(res));
                        if (res.data.errorCode == 100) {
                            goBackIndex();
                        }
                        reject(res);
                    }
                });
            },
            fail: res => {
                console.log("http request failed", code);
                console.log("not found code in storage");
                goBackIndex();
            }
        });
    });
};
複製程式碼

具體程式碼

有關本專案的具體程式碼(包含前後端,後端用的think.js框架,資料庫用的mysql)已經放在github上,如有需要,歡迎clone,歡迎star。

小程式前端:github.com/510team/wx-…

小程式後臺:github.com/510team/wec…

相關文章