《騰訊游戲人生》微信小程序開發總結


為打通游戲人生擂台賽與線下商家的O2O銜接,同時響應時下日臻火熱的微信小程序,項目團隊決定也開發一款針對性的微信小程序,以此方便商家在我們平台入駐並進行擂台賽事的創建和獎勵的核銷,進一步推廣擂台賽的玩法模式和渠道來源。以下是我們作為部門團隊內第一批吃螃蟹者,在這款微信小程序開發過程中踩過的一些坑以及總結,與大家一起分享,也歡迎指正和交流。

作者:一時兩無 | 騰訊互娛高級開發工程師 本文由微信平台開發發表在騰訊雲+社區

目前【騰訊游戲人生】小程序已經發布上線,大家可以掃小程序碼進行體驗。接下來主要介紹在開發該款小程序過程中的一些思考和積累。

img

一、基礎普及

1.1簡介

微信小程序是微信公眾平台推出除服務號、訂閱號、企業號外的第四種微信內應用類型,它是一種全新的連接用戶與服務的方式,它可以在微信內被便捷地獲取和傳播,同時具有出色的仿原生app的交互使用體驗和實用功能。

img

我們可以方便的在微信公眾平台進行小程序的注冊和提交資料,與微信公眾號的注冊流程較為一致。

1.2配置

用戶配置:小程序管理平台提供用戶管理功能,支持添加1個管理員,根據帳號類型和是否認證分別支持配置不同數目的開發者體驗者帳號權限,這些配置在小程序開發和內測階段十分有用,即是一個官方的白名單配置功能。

開發配置:與微信公眾號其他帳號開發接入配置類似,需要分別設置開發者ID和密鑰服務器域名配置開發消息接入地址等信息,可參考小程序開發文檔逐一設置,對於有開發公眾號經驗的同學來說也比較快速入手,只是需要注意這里的域名接入都必須要是https的服務域名地址

img

二、開發注意

2.1頁面模型

小程序包含一個描述整體程序的 app 和多個描述各自頁面的 page組成,可以看做是一系列頁面的組合集成,由一個全局app對象調度運行。頁面模型是小程序里的一個很重要的概念,從小程序配置文件app.json中也可以看到(如下所示),在app.json中注冊的頁面地址才可以被調用和打開展示。小程序的展示頁面主要分為tabbar頁常規頁兩種,而只有tabbar頁才會有底部tabbar顯示,兩類頁面對應的跳轉方式api也不同:

  • 對於tabbar頁地址(例 page/xxx/xxx),調用wx.switchTab(OBJECT)進行跳轉;
  • 對於常規頁地址(例 page/xxx/x1),調用wx.navigateTo(OBJECT)wx.redirectTo(OBJECT)進行跳轉
{
  "pages": [
    "page/xxx/x1",
    "page/yyy/y1"
  ],
  "window": {
    "navigationBarTitleText": "test"
  },
  "tabBar": {
    "list": [{
      "pagePath": "page/xxx/xxx",
      "iconPath": "image/xxx.png",
      "text": "tab1"
    }, {
      "pagePath": "page/yyy/yyy",
      "iconPath": "image/yyy.png",
      "text": "tab2"
    }]
  },
  "networkTimeout": {
    "request": 10000,
    "uploadFile": 10000
  },
  "debug": true
}

對於一個具體的頁面模型,都有其內部獨立的邏輯和數據作用域。主要包括四個組成文件,且必須要有相同的路徑目錄和文件名,例如:首頁對應/page/index/目錄下的index.js、index.wxml、index.wxss、index.json文件。

img

頁面的初始化、渲染、交互等邏輯都可以通過頁面js進行事件監聽和函數調用進行響應和處理,類似做web前端開發一樣,只是需要特別注意該js開發與web前端js開發的部分不同之處:

  • 頁面邏輯運行在Jscore中,非webview,無window、body、document等dom對象結構;
  • 無頁面cookie,無法設置網絡請求header的refer
  • 不支持類似jquery、zepto等對象拾取插件和操作方式,視圖更新通過數據綁定方式實現;
  • 頁面展示結構主要由官方原生組件拼裝展示,並通過對應支持的有限的事件函數進行響應控制,擴展化較低;
  • 頁面數據的改變通過調用Page.setData函數回顯頁面組件展示,頁面組件的動作事件值;e.detail.value可以傳遞給事件響應函數重設頁面數據,以此達到頁面數據和組件的聯動綁定

2.2生命周期

小程序的運行和各頁面的展示都有其特定的生命周期,並通過一系列的聲明周期函數進行調度控制。例如app全局實例的onLaunch、onShow、onHide等監聽函數來響應小程序初始化和顯影時的控制邏輯。而對於page頁面則擁有更為豐富的監聽調控函數,實現頁面生命周期中更多情況的控制處理。

函數定義 函數功能
onLoad 生命周期函數--監聽頁面加載
onReady 生命周期函數--監聽頁面初次渲染完成
onShow 生命周期函數--監聽頁面顯示
onHide 生命周期函數--監聽頁面隱藏
onUnload 生命周期函數--監聽頁面卸載
onPullDownRefresh 頁面相關事件處理函數--監聽用戶下拉觸底動作
onReachBottom 頁面相關事件處理函數--監聽用戶上拉觸底動作

下圖說明了小程序page頁面實例的生命周期運作:

img

而針對小程序內部的多個頁面之間的切換展示管理,則由小程序框架路由和頁面棧控制托管,並通過路由標簽或導航方式api函數進行頁面切換。需要注意的是頁面初始化第一次onLoad后如果只是onHide在后台不展示而並未onUnload銷毀,下次再切回該頁面展示時,不會再觸發onLoad監聽,而是觸發onShow監聽;onShow在頁面的初始化或每次展示時都會觸發,因此這里有個小技巧,部分需要實時更新展示到頁面的數據可在onShow中進行獲取處理。

img

三、數據處理

3.1數據請求

小程序里的網絡請求主要由wx.request(OBJECT)、wx.uploadFile(OBJECT)等api訪問小程序配置的https域名url接口實現。前者類似於ajax請求,后者通常用來上傳圖片文件等。這里請求API有些坑需要注意:

  • 請求不支持設置header的refer;
  • 請求url不允許帶自定義端口,只能是默認80端口;
  • 請求content-type默認為'application/json',如需用POST請求則需改為'application/x-www-form-urlencoded''multipart/form-data',否則后台請求里得不到post數據;
  • 后台接收請求php里最好用json_decode(file_get_contents("php://input"))方式獲取完整的post數據,否則如果傳遞較為復雜的多層post數據結構體,直接用$_POST等可能導致獲取數據格式異常或失敗

小程序里的數據請求操作最好都需要進行登錄態安全校驗,我們在這里仿造之前做H5項目的微信授權校驗方式,把調用微信登錄和授權后獲得的openid等數據進行加密獲取一個ticket票據,並設有過期時間,小程序的每個數據請求則需要附加攜帶openid和該ticket參數在后台php里進行校驗,成功則正常進行后續請求和返回數據,失敗則告知小程序客戶端重新登錄和授權后再請求數據。校驗的核心算法也較為簡單,就是判斷在ticket有效期時間內是否滿足如下等式:

而登錄和授權后初始的ticket生成也即用的該算法左式生成,並返回小程序本地緩存記錄,下次請求可從緩存取出直接應用。

最后對小程序里的所有數據請求進行了處理,封裝了GET/POST請求的header設置、登錄態參數的附加和過期處理、請求loading效果的顯隱控制等邏輯,並設置在app全局對象的暴露方法httpRequest中,方便在各子頁面調用處理。

img

由於我們的小程序需要根據用戶身份展現不同狀態的tabbar首頁,因此需要把用戶身份信息的請求前置,這里設計了一個loading過渡頁面,且剛好在這個頁面進行了微信登錄和授權,並得到登錄態參數初始化,然后請求了用戶的身份后設置到app全局數據,並在tabbar首頁進行對應判斷和展示。

首頁-默認 首頁-待審核 首頁-已通過 首頁-已被拒

img

3.2頁面通信

我們的小程序里有需要商家注冊和創建擂台的功能頁面,需要填寫的信息和層級較多,不足以一屏展示和填寫,因此需要支持數據在跨頁面間的傳遞和調用的通信能力,且對數據進行完整、有效和安全的管理,並實時響應頁面更新展示。基於小程序本身提供的api和特點,也查閱了一些資料,主要得到如下幾種思路和方法:

類別 說明 優點 缺點
navigate跳轉+url參數 利用navigate標簽或api跳轉時附加需要的數據作為url參數一起跳轉 不需額外代碼或插件,代碼簡單 參數較多時url過長混亂、tabbar頁不支持url傳參數
緩存數據存儲公用 利用app的globalData全局數據或本地緩存Storage的api實現數據緩存和公用處理 全局或本地緩存數據獲取和改寫,操作便捷有條理,容易理解 需要在相關各頁面注意全局或緩存數據的改寫和銷毀,保持數據安全一致,避免被隨意改寫污染。
PubSub或watcher機制 利用事件發布訂閱或監聽機制,開發對應插件,各頁面引入插件對所需數據進行訂閱或監聽處理。 基於插件化數據驅動實現,頁面可按需加入訂閱或監聽數據的處理,單一數據源,便於調試 需引入額外插件,且需解決頁面多次show、hide等導致的重復訂閱或監聽綁定,有程序崩潰風險
頁面路由棧 利用小程序自帶getCurrentPages的api獲取頁面路由棧,並根據頁面序號獲取和操作所需頁面對象 代碼邏輯清晰,能更為便捷獲取和處理所需頁面對象的數據,數據只有原頁面對象單獨一份,且由其內部托管銷毀,無數據污染風險。在目標頁面對此數據的修改可通過setData實時響應更新到原頁面展示 需要稍微注意頁面棧深度變化和所需頁面對象的獲取

我們考慮到表單數據較多,且產品需求表單需要本地草稿的功能,下次再打開可顯示上次填寫數據,無需重新再次填寫,因此最終結合了緩存和頁面路由棧的功能進行實現。在表單主頁面A利用localStorage緩存托管表單全體數據formData,並在子頁面B用頁面棧getCurrentPages獲取和操作主頁面A的表單某塊子數據formData.subData,子頁面B的修改操作通過A.setData實時傳遞和通知主頁面A的刷新展示,主頁面A在onUnload中響應對localstoreage的修改保存,便於下次加載讀取。

img

四、代碼維護

4.1公用配置

小程序代碼中涉及的較多數據、參數、接口、文案等自定義信息,可做成統一本地化配置,放入app實例的全局數據中公用,便於各子頁面獲取處理,同時結合小程序loading初始化時進行遠程請求更新配置。這樣的好處是,可以兼容配置信息更新與否情況下的配置統一管理。當需要配置更新時,能從遠程拉取替換,而不需要修改小程序的代碼文件,重新再走代碼發布及等待審核的流程。

4.2傳圖組件

小程序中注冊商家資料和創建擂台時都涉及到了圖片的上傳處理,用到了小程序官方的傳圖樣式組件和API,同時需要調用統一的后台上傳圖片生成URL的接口。因此這里有必要可以進行組件模塊化封裝的代碼優化,便於在多個page頁面內引入調用。

  • picloader.wxml
<template name="picloader">
    <view class="weui-cells weui-cells_after-title">
        <view class="weui-cell">
            <view class="weui-cell__bd">
                <view class="weui-uploader">
                    <view class="weui-uploader__hd">
                        <view class="weui-uploader__title">{{title}}</view>
                    </view>
                    <view class="weui-uploader__bd">
                        <view class="weui-uploader__files">
                            <block wx:if="{{picture}}">
                                <view class="weui-uploader__file" bindtap="previewImage" data-obj="{{name}}">
                                    <image class="weui-uploader__img" src="{{picture}}" mode="aspectFill" />
                                </view>
                            </block>
                            <input id="{{name}}" name="{{name}}" hidden="{{true}}" value="{{picture}}"/>
                        </view>
                        <view class="weui-uploader__input-box">
                            <view class="weui-uploader__input" bindtap="chooseImage" data-obj="{{name}}"></view>
                        </view>
                    </view>
                </view>
            </view>
            <view class="weui-cell__ft"><icon type="{{validate}}"/></view>
        </view>
    </view>
</template>
  • picloader.js
const app = getApp();

function init(pageDelegate) {
  //1.初始化圖片上傳種子HASH值
  app.httpRequest({
      url:app.Utils.getRequestUrl("getUploadHash"),
      success: function( res ) {
          if(res.r== "0"){
              pageDelegate.setData({
                  _hash:res._hash
              });
          }
      },
  },false);

  //2.綁定選擇圖片事件
  pageDelegate.chooseImage = function (e) {
    var that = this;
    var uploadUrl = app.Config.uploadBase;
    var obj = e.currentTarget.dataset.obj;//修改對象名
    if (e.currentTarget.dataset.ratio) {//尺寸比例限制
      uploadUrl += "?size_ratio=" + e.currentTarget.dataset.ratio;
    }

    wx.chooseImage({
        sizeType: ['original', 'compressed'], // 可以指定是原圖還是壓縮圖,默認二者都有
        sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有
        count:1,
        success: function (res0) {
            // 返回選定照片的本地文件路徑列表,tempFilePath可以作為img標簽的src屬性顯示圖片
            app.uploadRequest({
                url:uploadUrl,
                filePath: res0.tempFilePaths[0],
                data:{
                    _hash:that.data._hash
                },
                success:function(res){
                    var picurl = res.url || "";
                    var tmpData = {};
                    tmpData["formData." + obj] = picurl;
                    that.setData(tmpData);
                    app.Utils.checkValid(obj, picurl,that);
                    if (res.r != "0" && res.msg){
                      wx.showModal({
                        title: '圖片上傳失敗',
                        content: res.msg,
                        showCancel: false,
                        success: function (res) {
                        }
                      });
                    }
                }
            })
        }
    })
  }

  //3.綁定預覽圖片事件
  pageDelegate.previewImage = function (e) {
    var obj = e.currentTarget.dataset.obj;//修改對象名
    var pic = this.data.formData[obj] || "";
    if(pic == ""){
        return false;
    }
    
    wx.previewImage({
        current: e.currentTarget.id,
        urls: [pic] // 需要預覽的圖片http鏈接
    });
  }
}

//模塊化
module.exports = {
  init: init
}
  • 使用示例wxml中:
<import src="/page/common/picloader.wxml"/>
<template is="picloader" data="{{title: '獎勵圖片上傳',picture:formData.award_pic,validate:validate.award_pic,name:'award_pic'}}"/>
  • 使用示例js中:
const app = getApp();
var picloader = require('/utils/picloader.js');

Page({
  data:{
      ...
  },
  onLoad:function(options){
      // 頁面初始化 options為頁面跳轉所帶來的參數

      //注冊圖片上傳組件
      picloader.init(this);
  },
  ...
})

4.3分片模版

小程序tabbar首頁的需求是根據不同的用戶身份展現不同狀態的首頁,有未入駐、待審核、審核通過、審核被拒四種狀態,而都需要對應到同一個tabbar首頁url。因此這里需要把四種狀態的頁面片段部分分別做成子模版wxml的形式,通過小程序的條件渲染(wx:if)機制根據用戶身份情況按條件調用對應子模版進行展示。

同時小程序較多頁面都有共同的頭部(banner圖)和尾部(聯系客服)等片段展示,因此這里也考慮把其做成對應的公用head和foot子模版wxml,便於多頁面include引用。

<view class="page">
    <include src="/page/common/head.wxml"/>
    <view class="weui-msg">
        <include wx:if="{{status == 1}}" src="subpage/wait.wxml"/>
        <include wx:elif="{{status == 2}}" src="subpage/success.wxml"/>
        <include wx:elif="{{status == 3}}" src="subpage/fail.wxml"/>
        <include wx:else src="subpage/default.wxml"/>
    </view>
</view>
<include src="/page/common/foot.wxml"/>

五、總結體會

【騰訊游戲人生】微信小程序開發已經結束,亟待補充產品條款以及發布審核上線。在整個摸索和開發過程中,碰到了許多與web開發不同的別扭之處,也填過不少坑,包括參與小程序實現的設計、重構和前端開發都是一個新的嘗試與體驗。也對此有一些思考和總結,具體如下歸納。目前感覺小程序比較適用於一些旨在更快速和有效推廣自己輕量功能的小應用模式,不適合較大較重邏輯和功能的開發應用。但相信隨着微信官方對小程序支持力度的不斷增加,小程序的功能和推廣也將得到進一步擴大,接入和開發成本的同步降低,也會受到越來越多的開發者歡迎和喜愛。

優勢 劣勢
接入門檻低,參照公眾號接入方便,當下熱潮 官方設定的配置和開發模式嚴格,需限定范圍內進行搭建
使用體驗較H5好,流暢度高,體積小,傳播效益快 功能體驗限於限有組件交互,定制擴展化較弱,相比原生app體驗及高級功能還是較少
學習成本低,代碼組織清晰,開發靈活度高,開發文檔明確 不支持web開發中部分常用的功能特性,有時開發有些不便和局限性。
微信官方支持度高,內嵌靈活,小程序閉環控制,數據隔離安全可靠 暫不支持跳轉H5網頁,以及外部APP等交互能力。

此文已由作者授權騰訊雲+社區發布,原文鏈接:https://cloud.tencent.com/developer/article/1145916?fromSource=waitui

歡迎大家前往騰訊雲+社區或關注雲加社區微信公眾號(QcloudCommunity),第一時間獲取更多海量技術實踐干貨哦~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM