界面展示
結(jié)合動態(tài)圖描述一下目前實現(xiàn)的功能:
2.1 主頁上半部分顯示用戶頭像與用戶名(和微信中的信息一致,這部分組件是工具自帶的,我們可以修改這部分組件和內(nèi)容,稍候會提到);下半部分顯示一個經(jīng)典的問候語“Hello World”,提供一個可點擊的按鈕“點擊獲取火車票”;
2.2 點擊按鈕后,通過事先指定的參數(shù)(調(diào)用了百度APIStore中去哪網(wǎng)火車票查詢接口,站-站查詢所需參數(shù)為始發(fā)地、目的地及時間)發(fā)送網(wǎng)絡(luò)請求,將獲取到的JSON數(shù)據(jù)按火車車次為節(jié)點進行解析并在新頁面顯示基本信息(除了詳細座位信息),為每個車次提供一個可點擊的按鈕“點擊查看座位信息”;
2.3 點擊某車次中的座位查詢按鈕后,會將該車次對應(yīng)的所有座位信息顯示在新頁面中;
2.4 點擊后兩個頁面左上角的“返回”按鈕可回到上一頁,這個功能也是工具自帶的;
順便提一下在博客園中插入動畫,上面的演示過程是一張格式為gif的圖片,像添加普通圖片一樣操作即可。錄制工具使用的是靈者Gif錄制,可以指定開始、停止時所需操作與區(qū)域等錄制信息。
3. 要點分析
關(guān)于微信小程序工具的使用及初始項目的結(jié)構(gòu)說明,網(wǎng)上資源已經(jīng)很豐富,這里不打算再啰嗦
下面開始講講我個人在學(xué)習(xí)與開發(fā)過程中認為值得分享與記錄的點,歡迎大小神們一起討論與指正,特別是講得不對或有待改善的地方。下面只給出和講的點直接相關(guān)的代碼,整體代碼可以到項目工程中去查看,建議大家自己調(diào)試一遍。
3.1 index
index是項目新建時自動生成的,作為小程序的啟動頁面。
3.1.1 index.wxml
首頁的頭像與用戶名,從上圖的演示過程可以看出我將微信的名字“***”改成了“用戶名”:
<view bindtap="bindViewTap" class="userinfo">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">用戶名</text> <!-- {{userInfo.nickName}}直接寫成“用戶名” -->
</view>
用戶名部分原本的內(nèi)容為{{userInfo.nickName}},{{key_name}}的作用是獲取關(guān)鍵字名為key_name對應(yīng)的值(數(shù)據(jù)一般以key_name:value的形式定義在wxml文件同目錄下js文件的data成員中,后面會講解),image顯示的頭像資源也是通過這種方式指定為src="{{userInfo.avatarUrl}}",程序中產(chǎn)生的數(shù)據(jù)可以在開發(fā)者工具頂部偏右的AppData欄中查看。
如果不需要從js文件中獲取數(shù)據(jù),那么可以像代碼中“用戶名”那樣直接寫入數(shù)據(jù)值,不過一般不推薦這樣做,因為像Android等平臺App在開發(fā)時會將數(shù)據(jù)值放入strings.xml等文件,目的是為了將數(shù)據(jù)與布局分離,布局和功能實現(xiàn)代碼分離,方便開發(fā)與維護。
組件中的class項用來設(shè)置其樣式,屬性名對應(yīng)的樣式信息定義在wxss文件中,除了可以使用定義在本目錄wxss文件中的樣式,還可以使用app.wxss文件中定義的。如果樣式只是在某頁面中使用,那么建議定義在其目錄下的wxss文件中,即局部作用域內(nèi);如果是多個頁面共同使用,即全局樣式,那么一般定義在主程序app.wxss文件中。class樣式可以指定組件的寬高、背景顏色等屬性,本文不再進行詳述。
在界面下方添加按鈕“點擊獲取火車票”組件:
<view class="gettrain-button" bindtap="getTrainInfo">
<text>點擊獲取火車票</text>
</view>
按鈕的目標是為了讓用戶可以點擊進行交互,至于使用button、text或其他組件,視具體需求而定。這里是利用text組件,文本內(nèi)容直接寫入了字串“點擊獲取火車票”,對于只有一個子組件的布局其實可以如下面代碼不用嵌套,一層布局搞定。一般來說嵌套層數(shù)越少,加載速度越快,這對移動程序的體驗是至關(guān)重要的。
<view class="gettrain-button" bindtap="getTrainInfo">
點擊獲取火車票
</view>
但如果在父容器下有多個子組件共享其定義的樣式,那么嵌套可以另代碼簡潔很多:
<view class="gettrain-button">
<text bindtap="getTrainInfo">點擊獲取火車票</text>
<text bindtap="getCarInfo">點擊獲取汽車票</text>
<text bindtap="getPlaneInfo">點擊獲取飛機票</text>
</view>
組件若要有點擊交互功能,須為其綁定事件響應(yīng)方法,常用的有單點--bindtap,長按--binglongtap。bindtap="getTrainInfo",雙引號中的文本是方法名稱,在js文件中以該名定義方法,做需要的處理即可。
3.1.2 index.js
實現(xiàn)wxml布局中按鈕“點擊獲取火車票”綁定的函數(shù)功能:
//獲取火車票函數(shù)
getTrainInfo: function() {
wx.request({
url: 'http://apis.baidu.com/qunar/qunar_train_service/s2ssearch',
header: {
apikey: '361cf2a2459552575b0e86e0f62302bc',
},
data: {
version: '1.0',
from: '北京',
to: '杭州',
date: '2016-11-15',
},
success: function(res) {
var json = res.data;
//將JSON類型轉(zhuǎn)為String類型用以url參數(shù)傳遞,否則傳遞后會變成[object Object]
var jsonString = JSON.stringify(json);
wx.navigateTo({
url: '../train/train?trainInfos='+jsonString,
});
},
});
},
我們先來看看微信小程序官網(wǎng)對于網(wǎng)絡(luò)請求方法--wx.request(OBJECT)的說明:
一般來說,wx api提供的方法默認會有一個Object參數(shù),需要時傳入,不需要時不傳便是。不過這對于像我這種Android開發(fā)者來說一開始有點不適應(yīng),怎么函數(shù)調(diào)用時都傳入一個{...}參數(shù),內(nèi)部各個項之間用逗號“,”分隔,代碼中的url、data等。
從代碼中看,發(fā)起網(wǎng)絡(luò)請求時傳入了圖中列出的四項參數(shù):url、header、data及success,不同需求傳入的參數(shù)也會不同。對于wx.request方法而言,需根據(jù)網(wǎng)絡(luò)請求目標來傳參數(shù)的是前四項:url、header、data及method。
以本案例利用百度APIStore去哪網(wǎng)火車票獲取站--站火車票信息來說(http://apistore.baidu.com/apiworks/servicedetail/697.html),其官網(wǎng)給出的接口調(diào)用的參數(shù)信息與格式如下:
將上面兩張圖中的信息結(jié)合起來看,參數(shù)是一一對應(yīng)的:
wx url——火車票查詢 接口地址;
header——請求參數(shù)header;
data——請求參數(shù)urlParam;
method——請求方法;
因為wx中的method參數(shù)默認是GET,和火車票查詢接口指定的一致,所以調(diào)用時可以省略。
而對于最后三個回調(diào)函數(shù):success、fail及comlete,代碼中添加了success,在請求成功時對數(shù)據(jù)進行處理。當(dāng)然,一般的程序還得對請求失敗的情況做處理。下面就來分析success方法中的代碼,包括JSON數(shù)據(jù)的轉(zhuǎn)換與新頁面的跳轉(zhuǎn),請求返回的數(shù)據(jù)以參數(shù)res的形式傳入到function中。先來看看res中包含了哪些信息,通過代碼console.log(res)可以將其打印在工具調(diào)試頁面的Console項中。
request--ok和statusCode--200表示請求成功,所以才會回調(diào)success方法。而data對象才是我們需要的數(shù)據(jù),更精確地說,data.data.trainList對象才是真正的火車票信息。
var json = res.data,獲取data對象(網(wǎng)絡(luò)請求返回的數(shù)據(jù)一般為JSON格式),賦給變量json;
var jsonString = JSON.stringify(json),將JSON類型對象暫時轉(zhuǎn)換為String類型,用來作為url的參數(shù)部分進行傳遞;一開始在這里耽擱了很久,不進行轉(zhuǎn)換直接傳的話在目標頁面獲取不到想要的數(shù)據(jù),下面會說明原因;
url: '../train/train?trainInfos='+jsonString,通過url指定的信息跳轉(zhuǎn)到對應(yīng)頁面,如果不需要額外參數(shù),直接寫url: '../train/train';如果只是傳遞簡單的值,可寫成url: '../train/train?param=123';
至此,如果網(wǎng)絡(luò)沒有問題,點擊按鈕便可以進行火車票的查詢并攜帶結(jié)果數(shù)據(jù)跳轉(zhuǎn)到新頁面了。
3.2 train
train是自定義新建的頁面,用來顯示火車票基本信息,注意新添的頁面需在app.json文件中進行配置。
"pages/train/train", //火車票車次信息頁面
"pages/seat/seat" //車次余票信息頁面
3.2.1 train.wxml
由于站--站火車票所有車次的始發(fā)站和終點站是一樣,如北京--杭州東,所以先在頁面頂部顯示站點信息:
<text class="train-item">出發(fā)地:{{trainList[0].from}}</text>
<text class="train-item">目的地:{{trainList[0].to}}</text>
trainList對象會在js文件中定義成data成員,值為上面最后一張圖中的JSON對象--trainList,即火車票車次數(shù)組,每個元素包含一個車次的具體信息。
接下來顯示每個車次的信息,以橫線作分隔(由于是以學(xué)習(xí)和測試為目的,所以就沒有在布局的美觀上下功夫,大家見諒):
<view class="line"></view>
<block wx:for="{{trainList}}" wx:for-item="train">
<text class="train-item">{{index+1}}. 車次:{{train.trainNo}}</text>
<text class="train-item">車型:{{train.trainType}}</text>
<text class="train-item">起始時間:{{train.startTime}}</text>
<text class="train-item">到站時間:{{train.endTime}}</text>
<text class="train-item">總時長:{{train.duration}}</text>
<view id="trainindex-{{index}}" class="getseat-button" bindtap="getSeatInfo">
<text>點擊查看座位信息</text>
</view>
<view class="line"></view>
</block>
第1、11行很簡單,在站點與車次、車次與車次之間添加橫線。
當(dāng)布局中的組件個數(shù)和js中的數(shù)據(jù)有關(guān),即在wxml中寫死組件不能滿足需求時,可以利用block和wx:for來進行組件的動態(tài)生成。
第2行wx:for="{{trainList}}"表示block塊中的組件可以使用數(shù)組trainList中的內(nèi)容,從下標0開始迭代,數(shù)據(jù)中有幾個元素,就會動態(tài)生成幾套組件。wx:for-item="train"指定數(shù)組中元素的名稱為train(默認的是item,指定的意義之一是可讀性強),后續(xù)獲取屬性值時可通過train.key_name的形式。
第3行開始添加組件,類型是text,值為{{index+1}}. 車次:{{train.trainNo}},前半部分用來標明每個車次的序號,從1開始;而index和item類似,是默認的迭代索引名稱,其實就是數(shù)組元素當(dāng)前的下標,從0開始。
后面幾行添加text組件和第3行差不多,但第8行有兩個點說一下:
*1 bindtap="getSeatInfo",綁定一個回調(diào)函數(shù),點擊時跳轉(zhuǎn)到新頁面,顯示當(dāng)前車次對應(yīng)的座位信息;
*2 id="trainindex-{{index}}",給組件指定id,可以看到之前的組件都沒有設(shè)置過該屬性(不需要就可以不設(shè)置),那么什么時候需要呢?其中一種情況,當(dāng)js中某組件綁定的回調(diào)方法需要得知是哪個組件觸發(fā)了自己的時候,比如第一點中的方法getSeatInfo,要想點擊某車次的查看座位信息按鈕后顯示出對應(yīng)的座位信息,就得知道點擊組件對應(yīng)的trainList數(shù)組下標,而這個需求,正好可以借助id和index屬性來實現(xiàn);
3.2.2 train.js
首先定義data成員trainList,用來接收index頁面?zhèn)鬟f過來的數(shù)據(jù):
trainList: []
頁面啟動時若有數(shù)據(jù)需要載入,那么得添加onLoad方法(一開始自動運行,在其中實現(xiàn)數(shù)據(jù)的加載與處理),否則可以不添加。
onLoad: function(options) {
var jsonString = options.trainInfos;
//將字串類型轉(zhuǎn)為JSON類型
var json = JSON.parse(jsonString);
this.setData({
trainList: json.data.trainList,
});
},
當(dāng)方法的調(diào)用者有參數(shù)傳入時,我們可以通過添加方法參數(shù)的形式來獲取。對于參數(shù)名,自動啟方法一般為options,組件回調(diào)方法一般為e(event)。
第2行獲取index頁面在打開train頁面時傳入的火車票信息參數(shù)trainInfos。
第4行將String類型對象轉(zhuǎn)換回JSON格式,之前在index頁面提到過,url傳的參數(shù)是由JSON格式對象轉(zhuǎn)換過來的String類型。
第6行將真正的火車票車次信息數(shù)組取出,賦給數(shù)據(jù)成員trainList。
注意:給數(shù)據(jù)成員賦值時,必須調(diào)用頁面自身的setData方法,否則就算賦值了也不會同步到wxml文件中去,這一點容易出錯且不好定位原因。
車次數(shù)組得到后,wxml文件就會根據(jù)組件的屬性設(shè)置顯示對應(yīng)的信息。再來看實現(xiàn)按鈕“點擊查看座位信息”對應(yīng)的回調(diào)方法:
getSeatInfo: function(e) {
var prefix = 'trainindex-';
var trainIndex = e.currentTarget.id.substring(prefix.length);
//輸出根據(jù)組件id獲取的車票索引,用以顯示詳細的座位信息
console.log(trainIndex);
var trainNo = this.data.trainList[trainIndex].trainNo;
var json = this.data.trainList[trainIndex].seatInfos;
//將JSON類型轉(zhuǎn)為String類型用以url參數(shù)傳遞,否則傳遞后會變成[object Object],同時傳遞車次
var jsonString = JSON.stringify(json);
wx.navigateTo({
url: '../seat/seat?'+'trainNo='+trainNo+'&seatInfos='+jsonString,
});
},
第2、3行獲取之前定義的組件id中的index部分,即點擊組件對應(yīng)的trainList數(shù)組的下標。當(dāng)然原先定義時也可以不添加前綴'trainindex-',完全是為了可讀性,因為當(dāng)項目越來越大時有個一目了然的標示總是不錯的。
第6、7行分別獲取車次信息的列車號與座位信息,他們稍候會被傳遞到seat頁面。
第9行同樣地將得到的JSON格式對象先轉(zhuǎn)換為String類型,讓其可以在url中作為可被正確傳遞的參數(shù)。
第11行打開新的頁面seat顯示座位信息,多個參數(shù)之間以“&”符號分隔。
3.2.3 train.json
主程序中app.json文件除了配置需要調(diào)用onLoad方法的頁面外,還指定了一些全局的window樣式。若某個頁面在自己的json文件中沒有定義局部的window屬性,或根本沒有json文件,那默認將使用全局的。
項目初始沒有為index生成json文件,因為其作為啟動頁,直接用全局的“WeChat”就好,其實index標題應(yīng)該是小程序的名稱,我們自己真正開發(fā)的程序肯定得取另一個名字。
可以看到,logs、train及seat都對標題進行了定義,結(jié)果就是會覆蓋掉全局的值。以train為例,其在json文件中定義標題為“站-站火車查詢信息”:
{
"navigationBarTitleText": "站-站火車查詢信息"
}
還有一點,頁面的json文件不需要也不能頁面配置屬性(Pages),只能設(shè)置window屬性,所以就可以省略window名稱,直接像上述代碼用{...}形式即可。
3.3 seat
seat頁面用來顯示某車次的座位信息,包括座位等級、票價及余票。通過train頁面的分析,相信大家對網(wǎng)絡(luò)請求,數(shù)據(jù)在頁面與頁面、wxml與js文件之間的傳遞漸漸熟悉了。而seat和train類似,沒有什么特別的地方,所以和logs一樣這里就不再講什么了。
4. 小感悟
微信小程序,雖然目前還不知道其在微信的接入口,但應(yīng)該和訂閱號、服務(wù)號以及企業(yè)號會有所不同。搜索打開使用,用完關(guān)閉,沒有移動app的安裝、下載等過程,微信流量大,輕便、易用等特性是其優(yōu)點。然而正是因為這個優(yōu)點,開發(fā)者擔(dān)心這有可能使得小程序不能夠像app那樣強大,畢竟接入口、審核機制、推廣成本以及最大允許內(nèi)存等這些還未確定的因素對一款應(yīng)用來說都是至關(guān)重要的。
對于初學(xué)者(如原先搞android開發(fā)),暫且不管上面提到的那些,在弄明白應(yīng)用需求的同時,得邁開并加快對前端知識學(xué)習(xí)的腳步了。
本文項目代碼獲取地址
Github:https://github.com/VincentWYJ/WXAppTrain.git;
Blog file:http://files.cnblogs.com/files/tgyf/WXAppTrain.rar;