微信小程式開發遇到的那些坑

風跡發表於2018-10-15

一、Webview內嵌H5頁面不可以使用微信支付

最近在做公司的小程式專案時,需要做一個充值頁面,打算直接複用微信公眾號上已經開發好的H5頁面,誰知在本地真機除錯的時候調到H5頁面能夠支付成功,但是提到體驗版和正式版後發現不能調起微信支付,最後查了很多文件發現小程式的web-view不支援微信支付,只能通過跳回小程式呼叫小程式支付的API。實現大體思路:在H5頁面獲取支付引數,然後判斷是否在小程式環境中,如果在,獲取到支付引數後返回到小程式並將支付引數傳給小程式,小程式呼叫wx.requestPayment(OBJECT)介面完成支付,需要注意的是,獲取支付引數的appId為小程式的appId.下面是我的實現方式:

  1. 在H5頁面引入JSSDK 1.3.2,判斷小程式環境,獲取支付引數,將支付引數返回給小程式,這裡需要注意的是“package”引數,因為其包含“=”,因此傳的時候注意使用encodeURIComponent編碼,獲取後decodeURIComponent解碼
  2. 在小程式新建一個空白page,在onLoad中獲取引數,獲取成功後發起微信支付請求
  3. 支付完成,處理相關邏輯

二、小程式獲取不到unionId

在小程式釋出到線上之後發現有些新使用者在登入頁面卡死,最後發現是沒有獲取到unionId,為什麼獲取不到unionId呢,看下微信對UnionId機制的原文解釋:
如果開發者擁有多個移動應用、網站應用、和公眾帳號(包括小程式),可通過unionid來區分使用者的唯一性,因為只要是同一個微信開放平臺帳號下的移動應用、網站應用和公眾帳號(包括小程式),使用者的unionid是唯一的。換句話說,同一使用者,對同一個微信開放平臺下的不同應用,unionid是相同的。
同一個微信開放平臺下的相同主體的App、公眾號、小程式,如果使用者已經關注公眾號,或者曾經登入過App或公眾號,則使用者開啟小程式時,開發者可以直接通過wx.login獲取到該使用者UnionID,無須使用者再次授權。
注意: 後邊這句話的描述
使用者關注過公眾號,或者曾經登入過App或公眾號,則使用者開啟小程式時,開發者可以直接通過wx.login獲取到該使用者UnionID
即:如果使用者沒有關注過公眾號,或者沒有登陸過App,通過wx.login是無法獲取到該使用者UnionID,只能通過wx.getUserInfo來獲取UnionId
經驗證,系統不存在UnionId的小程式使用者都是沒有關注公眾號或未在App中使用微信授權的使用者
解決方案:
獲取小程式UnionId獲取不到時,wx.getUserInfo可以獲取敏感資料,其中包含UnionId欄位。
實現:參考https://www.cnblogs.com/cai-r…連結描述

三、掃普通連結二維碼開啟小程式

(使用該功能,小程式必須已經是已釋出狀態)小程式提供了掃描普通二維碼跳轉小程式的功能,首先在微信公眾平臺配置二維碼規則,域名路徑必須是校驗檔案所在路徑,可以配置測試連結進行測試,可以配置最多5個測試連結,可以指定測試連結開啟的測試範圍(開發、測試、正式),必須是具有體驗許可權的使用者才可以進行測試,非體驗使用者進入正式版本。規則釋出後,配置符合規則的連結均可進入到小程式。

四、可拖拽元素遇上canvas二維碼

小程式官方元件movable-area、movable-view說明

剛開始做這個可拖拽元素的時候,是準備將其做成一個元件,在每個需要的地方引入即可,但是有一個很大的問題就是所在頁面有一個canvas生成的二維碼,原生元件在小程式中的層級是最高的,即不管怎麼佈局或者給z-index都是不生效的,所以拖拽元素拖拽過程中會在二維碼下面。
解決這個問題的過程中遇到了很多坑,首先想到的是小程式中有沒有直接生成二維碼圖片的外掛,有是有,但是我的字串太長了,生成的base64編碼均太長了,所以我還是用的weapp-qrcode.js外掛,這個外掛自帶匯出圖片的方法,用的就是wx.canvasToTempFilePath將畫布匯出生成圖片,頁面上canvas所在位置放置一個image元件,將canvas移到可視區域外面,但是生成的圖片一直是亂的,原來是我沒給canvas樣式的高度和寬度導致生成出現問題,但是這樣還是在一些安卓機上出現問題,呼叫wx.canvasToTempFilePath已經是在draw回撥之後了,但是還是需要給延時才可以,在這裡我給的500ms,基本上就可以了。
原生元件層級最高的問題解決了,但是又出現一個問題,就是可拖拽元素是一個元件,所在頁面又有很多按鈕,如果直接將可拖拽元件的層級設定最高,那麼按鈕就不可點選,如果不設定最高,那麼就不可拖拽了,有兩種方式可以解決,一種是將按鈕以插槽的方式放在元件中,另一種是不將拖拽元素寫成元件,之間將movable-area放在wxml的最外層,我採用的是第二種,如果每個按鈕都寫成插槽的話維護起來太麻煩了

五、微信小程式快取——-快取時效性

/**
 * 資料快取沒有設定有效期
 */
class Storage {
  /**
   * 獲取快取
   * @param String $key  key
   * @param String $def  若想要無快取時,返回預設值則get(`key`,`預設值`)(支援字串、json、陣列、boolean等等)
   * @return value;
   */
  get(key, def = ``) {
    const timeout = parseInt(wx.getStorageSync(`${key}__separator__`) || 0);

    // 過期失效
    if (timeout) {
      if (Date.now() > timeout) {
        this.remove(key);
        return;
      }
    }
    let value = wx.getStorageSync(key);
    return value ? value : def;
  }
  /**
   * 設定快取
   * @param String $key       key
   * @param String $value     value(支援字串、json、陣列、boolean等等)
   * @param Number $timeout   過期時間(單位:分鐘)不設定時間即為永久儲存
   * @return value;
   */
  put(key, value, timeout = 0) {
    let _timeout = parseInt(timeout);
    wx.setStorageSync(key, value);
    if (_timeout) {
      wx.setStorageSync(`${key}__separator__`, Date.now() + 1000 * 60 * _timeout);
    } else {
      wx.removeStorageSync(`${key}__separator__`);
    }

    return value;
  }

  remove(key) {
    wx.removeStorageSync(key);
    wx.removeStorageSync(`${key}__separator__`);
    return undefined;
  }
}
export {
  Storage
}

六、小程式跳轉另小程式遇到的坑(監聽返回)

場景:在跳轉另一個小程式之前需要呼叫介面獲取跳轉所需引數,在另一個小程式返回時需要重新呼叫介面或許引數。
問題:首先想到的是點選跳轉的時候呼叫介面,之後wx.navigateToMiniProgram跳轉,將介面返回資料攜帶上,但是,這種不是使用者直接觸發的跳轉,微信不支援。。。
然後,那就先在頁面的onload事件中直接呼叫一次,然後再監聽另一個小程式返回,再呼叫一次介面,文件上寫的很明白,監聽App.onShow就好了,於是我在該頁面的onshow直接wx.onAppShow監聽場景值為1038,但是!!!這裡遇到了巨坑,第一次返回,wx.onAppShow呼叫一次,第二次返回,wx.onAppShow呼叫兩次,第三次返回,wx.onAppShow呼叫三次,直接導致整個流程出問題了。。。
解決:思考了好久,決定不用wx.onAppShow監聽場景值的辦法,直接在該頁面直接定義一個變數,比如navigateToOther,預設為false,跳轉成功後置為true,然後在onshow裡判斷是否為true,如果為true,呼叫介面,將navigateToOther置為false。完美解決!!!

七、小程式H5頁面分享

H5頁面中的分享轉發按鈕不能直接分享給好友,只能用折中的方式來做,點選H5頁面的分享按鈕時,彈出提示框,指向右上角的轉發按鈕,並通過wx.miniProgram.postMessage將所需資訊傳送給小程式,使用者點選轉發按鈕時可以通過bindmessage接收到訊息
參考連結:小程式內嵌web-view之分享(2)

八、webview重新整理

小程式巢狀H5頁面時,有時頁面在來回切換時需要重新整理該H5頁面,但是微信未提供相關介面,但是可以通過折中的方式來實現。

首先,讓webview做條件渲染:

<web-view wx:if="{{url}}" src="{{url}}" />
  data: {
    base_url: config.kalatong_base_url + `……`,
    url: ``
  },

  /**
   * 生命週期函式--監聽頁面載入
   */
  onLoad: function(options) {
    let url = this.data.base_url + "#wechat_redirect"
    this.data.url = decodeURIComponent(url)
  },
  
  /**
   * 生命週期函式--監聽頁面顯示
   */
  onShow: function() {
    this.refreshWebview()
  },

需要重新整理時,先把url設為空,銷燬當前webview。然後再把url設為當前值。如下:

refreshWebview: function () {
    let tmpUrl = this.data.url;
    this.setData({
      url: ``
    });
    setTimeout(() => {
      this.setData({
        url: tmpUrl
      })
    }, 500);
  }

這樣便可以在不影響導航欄歷史的情況下重新整理頁面,也可以是跳轉url。
這裡setData之後,頁面內容的更新應該是非同步執行的,因此我們後一次修改url需要延時一小段時間,否則會出現error。
猜測setData後頁面實際更新應該是在下一次的requestAnimationFrame,因此如果頁面完全不卡頓可能16ms就可以了,保險起見,我設了100ms。
但是100ms也不保險,有些頁面會空白,最後置成500ms

相關文章