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