爲打通遊戲人生擂臺賽與線下商家的O2O銜接,同時響應時下日臻火熱的微信小程序,項目團隊決定也開發一款針對性的微信小程序,以此方便商家在咱們平臺入駐並進行擂臺賽事的建立和獎勵的核銷,進一步推廣擂臺賽的玩法模式和渠道來源。如下是咱們做爲部門團隊內第一批吃螃蟹者,在這款微信小程序開發過程當中踩過的一些坑以及總結,與你們一塊兒分享,也歡迎指正和交流。php
做者:一時兩無 | 騰訊互娛高級開發工程師 本文由微信平臺開發發表在騰訊雲+社區前端
目前【騰訊遊戲人生】小程序已經發布上線,你們能夠掃小程序碼進行體驗。接下來主要介紹在開發該款小程序過程當中的一些思考和積累。jquery
微信小程序是微信公衆平臺推出除服務號、訂閱號、企業號外的第四種微信內應用類型,它是一種全新的鏈接用戶與服務的方式,它能夠在微信內被便捷地獲取和傳播,同時具備出色的仿原生app的交互使用體驗和實用功能。web
咱們能夠方便的在微信公衆平臺進行小程序的註冊和提交資料,與微信公衆號的註冊流程較爲一致。ajax
用戶配置:小程序管理平臺提供用戶管理功能,支持添加1個管理員,根據賬號類型和是否定證分別支持配置不一樣數目的開發者和體驗者賬號權限,這些配置在小程序開發和內測階段十分有用,便是一個官方的白名單配置功能。算法
開發配置:與微信公衆號其餘賬號開發接入配置相似,須要分別設置開發者ID和密鑰、服務器域名配置、開發消息接入地址等信息,可參考小程序開發文檔逐一設置,對於有開發公衆號經驗的同窗來講也比較快速入手,只是須要注意這裏的域名接入都必需要是https的服務域名地址。json
小程序包含一個描述總體程序的 app 和多個描述各自頁面的 page組成,能夠看作是一系列頁面的組合集成,由一個全局app對象調度運行。頁面模型是小程序裏的一個很重要的概念,從小程序配置文件app.json中也能夠看到(以下所示),在app.json中註冊的頁面地址才能夠被調用和打開展現。小程序的展現頁面主要分爲tabbar頁和常規頁兩種,而只有tabbar頁纔會有底部tabbar顯示,兩類頁面對應的跳轉方式api也不一樣:小程序
{ "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文件。微信小程序
頁面的初始化、渲染、交互等邏輯均可以經過頁面js進行事件監聽和函數調用進行響應和處理,相似作web前端開發同樣,只是須要特別注意該js開發與web前端js開發的部分不一樣之處:api
小程序的運行和各頁面的展現都有其特定的生命週期,並經過一系列的聲明周期函數進行調度控制。例如app全局實例的onLaunch、onShow、onHide等監聽函數來響應小程序初始化和顯影時的控制邏輯。而對於page頁面則擁有更爲豐富的監聽調控函數,實現頁面生命週期中更多狀況的控制處理。
函數定義 | 函數功能 |
---|---|
onLoad | 生命週期函數--監聽頁面加載 |
onReady | 生命週期函數--監聽頁面初次渲染完成 |
onShow | 生命週期函數--監聽頁面顯示 |
onHide | 生命週期函數--監聽頁面隱藏 |
onUnload | 生命週期函數--監聽頁面卸載 |
onPullDownRefresh | 頁面相關事件處理函數--監聽用戶下拉觸底動做 |
onReachBottom | 頁面相關事件處理函數--監聽用戶上拉觸底動做 |
下圖說明了小程序page頁面實例的生命週期運做:
而針對小程序內部的多個頁面之間的切換展現管理,則由小程序框架路由和頁面棧控制託管,並經過路由標籤或導航方式api函數進行頁面切換。須要注意的是頁面初始化第一次onLoad後若是隻是onHide在後臺不展現而並未onUnload銷燬,下次再切回該頁面展現時,不會再觸發onLoad監聽,而是觸發onShow監聽;onShow在頁面的初始化或每次展現時都會觸發,所以這裏有個小技巧,部分須要實時更新展現到頁面的數據可在onShow中進行獲取處理。
小程序裏的網絡請求主要由wx.request(OBJECT)、wx.uploadFile(OBJECT)等api訪問小程序配置的https域名url接口實現。前者相似於ajax請求,後者一般用來上傳圖片文件等。這裏請求API有些坑須要注意:
小程序裏的數據請求操做最好都須要進行登陸態安全校驗,咱們在這裏仿造以前作H5項目的微信受權校驗方式,把調用微信登陸和受權後得到的openid等數據進行加密獲取一個ticket票據,並設有過時時間,小程序的每一個數據請求則須要附加攜帶openid和該ticket參數在後臺php裏進行校驗,成功則正常進行後續請求和返回數據,失敗則告知小程序客戶端從新登陸和受權後再請求數據。校驗的核心算法也較爲簡單,就是判斷在ticket有效期時間內是否知足以下等式:
而登陸和受權後初始的ticket生成也即用的該算法左式生成,並返回小程序本地緩存記錄,下次請求可從緩存取出直接應用。
最後對小程序裏的全部數據請求進行了處理,封裝了GET/POST請求的header設置、登陸態參數的附加和過時處理、請求loading效果的顯隱控制等邏輯,並設置在app全局對象的暴露方法httpRequest中,方便在各子頁面調用處理。
因爲咱們的小程序須要根據用戶身份展示不一樣狀態的tabbar首頁,所以須要把用戶身份信息的請求前置,這裏設計了一個loading過渡頁面,且恰好在這個頁面進行了微信登陸和受權,並獲得登陸態參數初始化,而後請求了用戶的身份後設置到app全局數據,並在tabbar首頁進行對應判斷和展現。
首頁-默認 | 首頁-待審覈 | 首頁-已經過 | 首頁-已被拒 |
咱們的小程序裏有須要商家註冊和建立擂臺的功能頁面,須要填寫的信息和層級較多,不足以一屏展現和填寫,所以須要支持數據在跨頁面間的傳遞和調用的通訊能力,且對數據進行完整、有效和安全的管理,並實時響應頁面更新展現。基於小程序自己提供的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的修改保存,便於下次加載讀取。
小程序代碼中涉及的較多數據、參數、接口、文案等自定義信息,可作成統一本地化配置,放入app實例的全局數據中公用,便於各子頁面獲取處理,同時結合小程序loading初始化時進行遠程請求更新配置。這樣的好處是,能夠兼容配置信息更新與否狀況下的配置統一管理。當須要配置更新時,能從遠程拉取替換,而不須要修改小程序的代碼文件,從新再走代碼發佈及等待審覈的流程。
小程序中註冊商家資料和建立擂臺時都涉及到了圖片的上傳處理,用到了小程序官方的傳圖樣式組件和API,同時須要調用統一的後臺上傳圖片生成URL的接口。所以這裏有必要能夠進行組件模塊化封裝的代碼優化,便於在多個page頁面內引入調用。
<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>
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 }
<import src="/page/common/picloader.wxml"/> <template is="picloader" data="{{title: '獎勵圖片上傳',picture:formData.award_pic,validate:validate.award_pic,name:'award_pic'}}"/>
const app = getApp(); var picloader = require('/utils/picloader.js'); Page({ data:{ ... }, onLoad:function(options){ // 頁面初始化 options爲頁面跳轉所帶來的參數 //註冊圖片上傳組件 picloader.init(this); }, ... })
小程序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),第一時間獲取更多海量技術實踐乾貨哦~