微信小程序開發總結


最近做了一個投票的微信小程序,開發過程主要還是參考官方文檔:https://mp.weixin.qq.com/debug/wxadoc/dev/ 由於一直是做 Android 開發的,所以寫小程序界面時還需要大概看一下前端的東西,對於這些東西微信自己也做了一些封裝,但總體來說差別不大,這里進行一下總結。

注冊並創建項目

登陸 https://mp.weixin.qq.com 進行注冊,獲取 AppID並在設置中進行一些配置(如服務器域名),下載小程序的開發工具,掃描二維碼登陸,創建新項目。在創建項目時可以選擇創建一個 quick start 項目,這樣會自動生成一個簡單的 demo,有助於我們了解項目的結構和組成。

 

框架

小程序的框架分為視圖層(View)和邏輯層(App Service),它提供了自己的視圖層描述語言 WXML 和 WXSS,以及基於 JavaScript 的邏輯層框架,並在視圖層與邏輯層間提供了數據傳輸和事件系統。

這里的 WXML 和 WXSS 類似於前端的 HTML 和 CSS,但是 WXML 只能使用微信自己定義的組件而不能使用 HTML 里面的標簽,WXSS 則和 CSS 無太大差別。

框架的核心是一個響應的數據綁定系統,也就是說當做數據修改的時候,只需要在邏輯層修改數據,視圖層就會做相應的更新。

代碼結構

 


圖片.png

上圖是我做的投票小程序里面的代碼結構:
1、一個小程序主體部分由 app.js、app.json、app.wxss 三個文件組成,必須放在項目的根目錄,分別是整個程序的邏輯、全局配置及樣式。

(1) app.js 是小程序的腳本代碼。通過App()函數用來注冊一個小程序,接受一個 Object 參數,指定小程序的生命周期函數等,如下圖所示。

 


圖片.png

類似於 Android 中 的 Application,我們可以在這個文件中監聽並處理小程序的生命周期函數、聲明全局變量。
其他地方使用時通過var app = getApp()即可獲取其實例,並調用其中定義的方法和變量,但不要調用生命周期的方法。在App()的外面還可以另外定義 function 和變量,但只能在本文件內使用。

(2) app.json 是對整個小程序的全局配置。我們可以在這個文件中配置小程序是由哪些頁面組成,配置小程序的窗口背景色,配置導航條樣式,配置默認標題。

 


圖片.png

pages 指定了小程序的組成頁面,第一個代表小程序的初始頁面。
window 用於設置小程序的狀態欄、導航條、標題、窗口背景色。
tabBar 用於配置客戶端窗口的底部或頂部 tab 欄的樣式以及 tab 切換時顯示的對應頁面。
另外還可以配置各種網絡請求的超時時間networkTimeout和是否開啟調試模式debug

(3) app.wxss 是整個小程序的公共樣式表。可以配置一些通用的樣式。

 


圖片.png

2、pages 里面則是小程序的各個頁面,其中 index 一般作為主界面(當然這並不是由名字決定的,而是在app.json里面配置的第一個page),可以看到,一個界面由 wxml、wxss、js、json 等四個文件組成,分別是頁面的邏輯、界面結構,樣式以及配置。小程序規定這四個文件必須具有相同的路徑和名字。

(1) js 是頁面的腳本代碼。通過Page()函數用來注冊一個頁面。接受一個 Object 參數,其指定頁面的初始數據、生命周期函數、事件處理函數等,如下圖所示。

 


圖片.png

其中data定義了頁面的初始數據,會以 JSON 的形式由邏輯層傳至渲染層,所以其數據必須是可以轉成 JSON 的格式:字符串,數字,布爾值,對象,數組。渲染層可以通過 WXML 對數據進行綁定。
onLoad、onShow、onReady、onHide、onUnload 是頁面的生命周期函數,分別在頁面加載、顯示、初次渲染完成、隱藏和卸載時調用。其中onLoadonReady只會在頁面加載時調用一次,onShow則每次顯示頁面都會調用一次。
onPullDownRefresh用於監聽用戶下拉刷新事件,需要在 json 配置文件中開啟enablePullDownRefresh。當處理完數據刷新后,wx.stopPullDownRefresh可以停止當前頁面的下拉刷新。
onShareAppMessage只有定義了該方法才會在微信的右上角菜單顯示分享按鈕,需要 return 一個 Object,用於自定義分享內容,包括title標題和path分享的頁面的完整路徑。
viewTap是事件處理函數,函數名是自己取的,在渲染層可以在組件中加入事件綁定<view bindtap="viewTap"> click me </view>,當達到觸發事件時,就會執行 Page 中定義的事件處理函數。
當需要改變data中的數據時,不能直接修改this.data,而需要調用this.setData()方法進行修改。
Page()的外面同樣可以另外定義 function 和變量,也只能在本文件內使用。

(2) wxml 是頁面的布局文件,只能使用微信自己定義的組件。https://mp.weixin.qq.com/debug/wxadoc/dev/component/ 這里是微信提供的所有組件的列表和屬性,其中使用得最多的是 view 以及一些表單組件如 button 等等。具體的布局方式跟HTML差不多,這里不再多說。

(3) wxss 是樣式表,具有 CSS 大部分特性,並進行了特性擴展,主要包括:
① 尺寸單位:rpx(responsive pixel)可以根據屏幕寬度進行自適應。規定屏幕寬為750rpx。如在 iPhone6 上,屏幕寬度為375px,共有750個物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
② 樣式導入:使用@import語句可以導入外聯樣式表,@import后跟需要導入的外聯樣式表的相對路徑,用;表示語句結束。例如:

/** common.wxss **/ .small-p { padding:5px; } /** app.wxss **/ @import "common.wxss"; .middle-p { padding:15px; }

定義在 app.wxss 中的樣式為全局樣式,作用於每一個頁面。在 page 的 wxss 文件中定義的樣式為局部樣式,只作用在對應的頁面,並會覆蓋 app.wxss 中相同的選擇器。

(4) json 是頁面的配置文件,頁面的配置比app.json全局配置簡單得多,只是設置 app.json 中的 window 配置項的內容,頁面中配置項會覆蓋 app.json 的 window 中相同的配置項,無需寫 window 這個鍵。上面說的開啟下拉刷新功能就需要在這個文件里面進行配置:

 


圖片.png

由於是 json 格式的文件,即使不需要配置任何東西也需要寫{},否則會報錯。

3、utils 里面包含了一些將公共的代碼抽離出來的 js 文件,作為一個模塊可以方便被任何地方使用。模塊只有通過 module.exports 才能對外暴露接口。下圖即為utils/util.js文件中的內容,包含了一個formatDate的方法,並將方法 exports 給外部使用。

 


圖片.png

在其他地方使用時需要通過var utils = require('../../utils/util.js');進行引用,之后就可以通過變量 utils 調用 util.js 文件中定義的方法。

4、images 里面則放了一些圖片資源。

數據綁定

WXML 中的動態數據均來自對應 Page 的 data。數據綁定使用雙大括號將變量包起來,可以作用於內容、組件屬性(需要在雙引號之內)、控制屬性(需要在雙引號之內)、關鍵字(需要在雙引號之內)。
例如:

Page({ data: { message: "Hello", id: 0, condition: true } }) <view> {{message}} </view> <view id="item-{{id}}"> </view> <view wx:if="{{condition}}"> </view> <checkbox checked="{{condition}}"> </checkbox>

還可以在 {{}} 內進行簡單的運算,如:

Page({
  data: { flag: true, a: 1, b: 2, c: 3 length: 6, name: 'MINA', object: { key: 'Hello ' }, array: ['MINA'] } }) <view hidden="{{flag ? true : false}}"> Hidden </view> <view> {{a + b}} + {{c}} + d </view> // 結果為3 + 3 + d <view wx:if="{{length > 5}}"> </view> <view>{{"hello" + name}}</view> <view>{{object.key}} {{array[0]}}</view>

條件渲染

在框架中,我們用 wx:if="{{condition}}" 來判斷是否需要渲染該代碼塊:

<view wx:if="{{condition}}"> True </view>

也可以用 wx:elif 和 wx:else 來添加一個 else 塊:

<view wx:if="{{length > 5}}"> 1 </view> <view wx:elif="{{length > 2}}"> 2 </view> <view wx:else> 3 </view>

因為 wx:if 是一個控制屬性,需要將它添加到一個標簽上。但是如果我們想一次性判斷多個組件標簽,我們可以使用一個 <block/> 標簽將多個組件包裝起來,並在上邊使用 wx:if 控制屬性。

<block wx:if="{{true}}"> <view> view1 </view> <view> view2 </view> </block>

注意: <block/> 並不是一個組件,它僅僅是一個包裝元素,不會在頁面中做任何渲染,只接受控制屬性。

一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在運行時條件不大可能改變則 wx:if 較好。

列表渲染

在組件上使用wx:for控制屬性綁定一個數組,即可使用數組中各項的數據重復渲染該組件。
默認數組的當前項的下標變量名默認為index,數組當前項的變量名默認為item

<view wx:for="{{array}}"> {{index}}: {{item.message}} </view> Page({ data: { array: [{ message: 'foo', }, { message: 'bar' }] } })

使用 wx:for-item 可以指定數組當前元素的變量名,使用 wx:for-index 可以指定數組當前下標的變量名:

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"> {{idx}}: {{itemName.message}} </view>

wx:for也可以嵌套,下邊是一個九九乘法表

<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i"> <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j"> <view wx:if="{{i <= j}}"> {{i}} * {{j}} = {{i * j}} </view> </view> </view>

類似block wx:if,也可以將wx:for用在<block/>標簽上,以渲染一個包含多節點的結構塊。例如:

<block wx:for="{{[1, 2, 3]}}"> <view> {{index}}: </view> <view> {{item}} </view> </block>

如果列表中項目的位置會動態改變或者有新的項目添加到列表中,並且希望列表中的項目保持自己的特征和狀態(如 <input/> 中的輸入內容,<switch/> 的選中狀態),需要使用 wx:key 來指定列表中項目的唯一的標識符。wx:key 的值以兩種形式提供:
① 字符串,代表在 for 循環的 array 中 item 的某個 property,該 property 的值需要是列表中唯一的字符串或數字,且不能動態改變。
② 保留關鍵字 *this 代表在 for 循環中的 item 本身,這種表示需要 item 本身是一個唯一的字符串或者數字。

Page({
  data: {
    objectArray: [
      {id: 0, unique: 'unique_0'}, {id: 1, unique: 'unique_1'}, {id: 2, unique: 'unique_2'}, ], numberArray: [1, 2, 3, 4] } }) <switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch> <switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch>

事件

上面簡單提到過 <view> 的事件綁定,通常在組件中綁定一個事件處理函數,在相應的Page定義中寫上相應的事件處理函數,參數是event。

事件分為冒泡事件(當一個組件上的事件被觸發后,該事件會向父節點傳遞)和非冒泡事件(當一個組件上的事件被觸發后,該事件不會向父節點傳遞)。
冒泡事件有:touchstart(手指觸摸動作開始)、touchmove(手指觸摸后移動)、touchcancel(手指觸摸動作被打斷,如來電提醒,彈窗)、touchend(手指觸摸動作結束)、tap(手指觸摸后馬上離開)、longtap(手指觸摸后,超過350ms再離開)。
除此之外其他組件自定義事件如無特殊申明都是非冒泡事件,如<form/>的submit事件,<input/>的input事件,<scroll-view/>的scroll事件。

事件綁定的寫法同組件的屬性,以 key、value 的形式。key 以 bind 或 catch 開頭事件的類型結尾,如bindtap, catchtouchstart,value 是一個字符串,需要在對應的 Page 中定義同名的函數。
bind 事件綁定不會阻止冒泡事件向上冒泡,catch 事件綁定可以阻止冒泡事件向上冒泡。

當組件觸發事件時,邏輯層綁定該事件的處理函數會收到一個事件對象。
BaseEvent 基礎事件對象的屬性包括type(事件類型)、timeStamp(事件生成時的時間戳)、target(觸發事件的組件的一些屬性值集合)、currentTarget(當前組件的一些屬性值集合)。
CustomEvent 自定義事件對象繼承自BaseEvent,並增加了 detail(額外的信息) 屬性。
TouchEvent 觸摸事件對象繼承自BaseEvent,並增加了 touches(觸摸事件,當前停留在屏幕中的觸摸點信息的數組)和 changedTouches(觸摸事件,當前變化的觸摸點信息的數組) 屬性。

dataset 在組件中可以定義數據,以data-開頭,多個單詞由連字符-連接,不能有大寫(大寫會自動轉成小寫) 如data-element-type,最終在 event.target.dataset 中會將連字符轉成駝峰elementType。

登陸

小程序的登錄流程如下圖所示:

 


login.png

以下是我的登陸方法,放在 util.js 中,並傳入了一個 function 的參數 cb 作為登陸成功時的回調。如果不需要回調則不傳即可。通常會在程序啟動時調用一次(可以在 app.js 的 onLaunch 中,也可以在 index.js 的onLoad 中),之后在任何請求中碰到 access_token 過期或無效時再調用。

function login(cb) { wx.login({ success: function (res) { var code = res.code; if (code) { wx.getUserInfo({ success: function (res) { var userInfo = res.userInfo; wx.setStorageSync('user', userInfo); wx.request({ url: 'https://server-host/login', data: { 'code': code, 'user_info': userInfo }, method: 'POST', success: function (res) { if (res.data.data && res.data.data.access_token) { wx.setStorageSync('accessToken', res.data.data.access_token); typeof cb == 'function' && cb(); } else { showFailedToast('服務器登陸失敗,請退出后重新登錄'); } }, fail: function (e) { showFailedToast('服務器登陸失敗,請退出后重新登錄'); } }) }, fail: function (e) { showFailedToast('獲取用戶信息失敗,請退出后重新登錄'); } }) } else { showFailedToast('獲取微信登錄狀態失敗,請退出后重新登錄'); } }, fail: function (e) { showFailedToast('微信登陸失敗,請退出后重新登錄'); } }) }

1、微信小程序需要調用 wx.login() 進行登錄,成功后會返回一個 code。
2、通過 wx.getUserInfo() 獲取用戶信息,雖然這個 API 不需要用到 code,但也只能在 wx.login 成功后才能調用。獲取 userInfo 后,可以通過 wx.setStorageSync() 將用戶信息保存到本地緩存中。
3、通過 wx.request() 請求服務器的登錄api,將 code 和 userInfo 傳過去,服務器會生成一個access_token(即上圖中的3rd_session,命名可以按照各自的習慣) 返回,之后通過 wx.setStorageSync() 將這個 access_token 保存到本地緩存中。
4、之后在任何地方進行請求服務器的操作,都可以通過 wx.getStorageSync() 將本地保存的 access_token 取出來並作為參數帶上。
5、由於 access_token 存在過期的問題,因此可以與服務器約定一個特殊的 sta,比如 -500,作為 access_token 過期的標識,在任何請求中,碰到返回的 sta 為 -500 時,就可以重新調用 login 方法,傳入一個登陸成功后的回調 function 作為參數,獲取新的 access_token 保存,並在登陸成功后的回調 function 中再次發送請求。代碼如下:

function loadDetail(self) { wx.request({ url: 'https://server-host/detail', data: { 'vid': self.data.vid, 'access_token': wx.getStorageSync('accessToken') }, method: 'GET', success: function (res) { if (res.data.sta == -500) { utils.login(function () { loadDetail(self); }) return; } ... }, fail: function () { ... }) }

API

以上登陸過程中提到了幾個比較常用的微信API,如 wx.login()、wx.getUserInfo()、wx.setStorageSync()、wx.getStorageSync()、wx.request() 等,另外還有很多的API,在 https://mp.weixin.qq.com/debug/wxadoc/dev/api/ 中寫的很清楚,這里就不一一說明了,大家用的時候查看一下文檔即可。


免責聲明!

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



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