微信小程序--火車票查詢

原文:http://www.cnblogs.com/tgyf/p/5960979.htmlcss

寫在最前面html

微信小程序自九月份推出內測資格以來,經歷了輿論熱潮到如今看似冷清,但並不意味着你們不那麼關注或者不關注了。我想無論是否有內測資格,只要是感興趣的開發者已經進入潛心耕耘產品的階段了,至少是靜下心來思考與學習。若是對微信小程序的前途和定位有什麼疑惑,能夠看看這篇文章http://lib.csdn.net/article/wechat/46742前端

下面從字母a開始編號的內容主要做爲後續學習與思考後對文章作的更新,包括項目的改進、觀點的補充等,因此建議你們先將整篇文章看完再來瀏覽這部分,會有不同的收穫。android

a. 3.1.2節index.js實現火車票查詢事件的響應函數getTrainInfo時,直接在函數體中調用wx.request方法開始網絡請求。可是後面在閱讀了別人的代碼後發現,能夠將經常使用的url、apikey、request等常量和方法抽象出來,定義到獨立的文件當中。因而在根目錄下新建requests目錄,其中新建文件request與api文件(js格式),api用來定義網路請求所需的url、apikey等常量信息,request用來定義網絡請求方法(能夠多種形式)。這樣在不一樣頁面中請求不一樣網絡數據時,只要傳不一樣的參數便可,調用的方法是共用的,提升了可讀性與維護性。這部分改變已經同步更新到了Github。css3

b. 3.1.2和3.2.2節都提到了,將JSON格式數據做爲url參數傳遞前,須要先轉化爲String類型,而後目標頁面讀取數據時須要將String類型對象轉回到JSON格式。若是不想這麼複雜,而又只是以學習爲目的的話,能夠藉助app.js中定義的全局變量來承載數據,由於項目的任何地方均可以獲取這種變量值。git

app中添加相關變量trainList:github

1 globalData:{
2   userInfo:null,
3   trainList:[]  //火車票信息列表
4 }

index頁面獲取網絡請求返回數據後直接對全局變量賦值:json

1 app.globalData.trainList = res.data.data.trainList;

train頁面獲取:小程序

1 this.setData({
2   trainList: app.globalData.trainList,
3 });

這樣就避免了轉化的步驟,可是若是是正規大型項目,仍是建議採用最合適的處理方式,畢竟全局變量是針對整個項目的。 微信小程序

 

 

1. 相關連接

本文項目代碼獲取地址

Github:https://github.com/VincentWYJ/WXAppTrain.git

Blog file:http://files.cnblogs.com/files/tgyf/WXAppTrain.rar

 

微信小程序開發學習資料

微信開發者平臺:https://mp.weixin.qq.com/debug/wxadoc/dev/framework/config.html?t=1475052055990,小程序開發工具能夠在裏面下載,值得高興的是新版本已經再也不須要藉助安裝0.7版本進行先登陸,而是能夠直接登陸來開發與調試;

Flex css layout:http://www.w3cplus.com/css3/flexbox-basics.html,像我這樣的非前段開發者,對於Flex layout的使用得先花時間學習一番,否則連最基本的組件佈局都比較困難,更不要說設計出美觀、交互性強的界面;

小程序:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1474632113_xQVCl&token=&lang=zh_CN,點擊提示沒法打開/回到首頁的話請複製粘貼到地址欄進行打開,這裏面的內容能夠說是和第一個連接中的內容相輔相成,邊學邊用吧;

 

 

2. 界面展現

 

 結合動態圖描述一下目前實現的功能:

2.1 主頁上半部分顯示用戶頭像與用戶名(和微信中的信息一致,這部分組件是工具自帶的,咱們能夠修改這部分組件和內容,稍候會提到);下半部分顯示一個經典的問候語「Hello World」,提供一個可點擊的按鈕「點擊獲取火車票」;

2.2 點擊按鈕後,經過事先指定的參數(調用了百度APIStore中去哪網火車票查詢接口,站-站查詢所需參數爲始發地、目的地及時間)發送網絡請求,將獲取到的JSON數據按火車車次爲節點進行解析並在新頁面顯示基本信息(除了詳細座位信息),爲每一個車次提供一個可點擊的按鈕「點擊查看座位信息」;

2.3 點擊某車次中的座位查詢按鈕後,會將該車次對應的全部座位信息顯示在新頁面中;

2.4 點擊後兩個頁面左上角的「返回」按鈕可回到上一頁,這個功能也是工具自帶的;

 

順便提一下在博客園中插入動畫,上面的演示過程是一張格式爲gif的圖片,像添加普通圖片同樣操做便可。錄製工具使用的是靈者Gif錄製,能夠指定開始、中止時所需操做與區域等錄製信息。

 

 

3. 要點分析

關於微信小程序工具的使用及初始項目的結構說明,網上資源已經很豐富,這裏不打算再囉嗦,有不瞭解的能夠參考:

http://www.cnblogs.com/dragondean/p/5919694.html

 

下面開始講講我我的在學習與開發過程當中認爲值得分享與記錄的點,歡迎大小神們一塊兒討論與指正,特別是講得不對或有待改善的地方。下面只給出和講的點直接相關的代碼,總體代碼能夠到項目工程中去查看,建議你們本身調試一遍。

 

3.1 index

index是項目新建時自動生成的,做爲小程序的啓動頁面。

3.1.1 index.wxml

首頁的頭像與用戶名,從上圖的演示過程能夠看出我將微信的名字「***」改爲了「用戶名」:

1 <view  bindtap="bindViewTap" class="userinfo">
2   <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
3   <text class="userinfo-nickname">用戶名</text>  <!-- {{userInfo.nickName}}直接寫成「用戶名」 -->
4 </view>

用戶名部分本來的內容爲{{userInfo.nickName}},{{key_name}}的做用是獲取關鍵字名爲key_name對應的值(數據通常以key_name:value的形式定義在wxml文件同目錄下js文件的data成員中,後面會講解),image顯示的頭像資源也是經過這種方式指定爲src="{{userInfo.avatarUrl}}",程序中產生的數據能夠在開發者工具頂部偏右的AppData欄中查看。

若是不須要從js文件中獲取數據,那麼能夠像代碼中「用戶名」那樣直接寫入數據值,不過通常不推薦這樣作,由於像Android等平臺App在開發時會將數據值放入strings.xml等文件,目的是爲了將數據與佈局分離,佈局和功能實現代碼分離,方便開發與維護。

組件中的class項用來設置其樣式,屬性名對應的樣式信息定義在wxss文件中,除了可使用定義在本目錄wxss文件中的樣式,還可使用app.wxss文件中定義的。若是樣式只是在某頁面中使用,那麼建議定義在其目錄下的wxss文件中,即局部做用域內;若是是多個頁面共同使用,即全局樣式,那麼通常定義在主程序app.wxss文件中。class樣式能夠指定組件的寬高、背景顏色等屬性,本文再也不進行詳述。

在界面下方添加按鈕「點擊獲取火車票」組件:

1 <view class="gettrain-button" bindtap="getTrainInfo">
2   <text>點擊獲取火車票</text>
3 </view>

按鈕的目標是爲了讓用戶能夠點擊進行交互,至於使用button、text或其餘組件,視具體需求而定。這裏是利用text組件,文本內容直接寫入了字串「點擊獲取火車票」,對於只有一個子組件的佈局其實能夠以下面代碼不用嵌套,一層佈局搞定。通常來講嵌套層數越少,加載速度越快,這對移動程序的體驗是相當重要的。

1 <view class="gettrain-button" bindtap="getTrainInfo">
2   點擊獲取火車票
3 </view>

但若是在父容器下有多個子組件共享其定義的樣式,那麼嵌套能夠另代碼簡潔不少:

1 <view class="gettrain-button">
2   <text bindtap="getTrainInfo">點擊獲取火車票</text>
3   <text bindtap="getCarInfo">點擊獲取汽車票</text>
4   <text bindtap="getPlaneInfo">點擊獲取飛機票</text>
5 </view>

組件若要有點擊交互功能,須爲其綁定事件響應方法,經常使用的有單點--bindtap,長按--binglongtap。bindtap="getTrainInfo",雙引號中的文本是方法名稱,在js文件中以該名定義方法,作須要的處理便可。

3.1.2 index.js

 實現wxml佈局中按鈕「點擊獲取火車票」綁定的函數功能:

複製代碼
 1 //獲取火車票函數
 2 getTrainInfo: function() {
 3     wx.request({
 4         url: 'http://apis.baidu.com/qunar/qunar_train_service/s2ssearch',
 5         header: {
 6             apikey: '361cf2a2459552575b0e86e0f62302bc',
 7         },
 8         data: {
 9             version: '1.0',
10             from: '北京',
11             to: '杭州',
12             date: '2016-11-15',
13         },
14         success: function(res) {
15             var json = res.data;
16             //將JSON類型轉爲String類型用以url參數傳遞,不然傳遞後會變成[object Object]
17             var jsonString = JSON.stringify(json);
18             wx.navigateTo({
19                 url: '../train/train?trainInfos='+jsonString,
20             });
21         },
22     });
23 },
複製代碼

咱們先來看看微信小程序官網對於網絡請求方法--wx.request(OBJECT)的說明:

 通常來講,wx api提供的方法默認會有一個Object參數,須要時傳入,不須要時不傳即是。不過這對於像我這種Android開發者來講一開始有點不適應,怎麼函數調用時都傳入一個{...}參數,內部各個項之間用逗號「,」分隔,代碼中的url、data等。

從代碼中看,發起網絡請求時傳入了圖中列出的四項參數:url、header、data及success,不一樣需求傳入的參數也會不一樣。對於wx.request方法而言,需根據網絡請求目標來傳參數的是前四項:url、header、data及method。

以本案例利用百度APIStore去哪網火車票獲取站--站火車票信息來講(http://apistore.baidu.com/apiworks/servicedetail/697.html),其官網給出的接口調用的參數信息與格式以下:

將上面兩張圖中的信息結合起來看,參數是一一對應的:

wx url——火車票查詢 接口地址;

header——請求參數header;

data——請求參數urlParam;

method——請求方法;

由於wx中的method參數默認是GET,和火車票查詢接口指定的一致,因此調用時能夠省略。

而對於最後三個回調函數:success、fail及comlete,代碼中添加了success,在請求成功時對數據進行處理。固然,通常的程序還得對請求失敗的狀況作處理。下面就來分析success方法中的代碼,包括JSON數據的轉換與新頁面的跳轉,請求返回的數據以參數res的形式傳入到function中。先來看看res中包含了哪些信息,經過代碼console.log(res)能夠將其打印在工具調試頁面的Console項中。

request--ok和statusCode--200表示請求成功,因此纔會回調success方法。而data對象纔是咱們須要的數據,更精確地說,data.data.trainList對象纔是真正的火車票信息。

var json = res.data,獲取data對象(網絡請求返回的數據通常爲JSON格式),賦給變量json;

var jsonString = JSON.stringify(json),將JSON類型對象暫時轉換爲String類型,用來做爲url的參數部分進行傳遞;一開始在這裏耽擱了好久,不進行轉換直接傳的話在目標頁面獲取不到想要的數據,下面會說明緣由;

url: '../train/train?trainInfos='+jsonString,經過url指定的信息跳轉到對應頁面,若是不須要額外參數,直接寫url: '../train/train';若是隻是傳遞簡單的值,可寫成url: '../train/train?param=123';

至此,若是網絡沒有問題,點擊按鈕即可以進行火車票的查詢並攜帶結果數據跳轉到新頁面了。

 

3.2 train

train是自定義新建的頁面,用來顯示火車票基本信息,注意新添的頁面需在app.json文件中進行配置。

1 "pages/train/train",  //火車票車次信息頁面
2 "pages/seat/seat"  //車次餘票信息頁面

3.2.1 train.wxml

因爲站--站火車票全部車次的始發站和終點站是同樣,如北京--杭州東,因此先在頁面頂部顯示站點信息:

1 <text class="train-item">出發地:{{trainList[0].from}}</text>
2 <text class="train-item">目的地:{{trainList[0].to}}</text>

trainList對象會在js文件中定義成data成員,值爲上面最後一張圖中的JSON對象--trainList,即火車票車次數組,每一個元素包含一個車次的具體信息。

接下來顯示每一個車次的信息,以橫線做分隔(因爲是以學習和測試爲目的,因此就沒有在佈局的美觀上下功夫,你們見諒):

複製代碼
 1 <view class="line"></view>
 2 <block wx:for="{{trainList}}" wx:for-item="train">
 3     <text class="train-item">{{index+1}}. 車次:{{train.trainNo}}</text>
 4     <text class="train-item">車型:{{train.trainType}}</text>
 5     <text class="train-item">起始時間:{{train.startTime}}</text>
 6     <text class="train-item">到站時間:{{train.endTime}}</text>
 7     <text class="train-item">總時長:{{train.duration}}</text>
 8     <view id="trainindex-{{index}}" class="getseat-button" bindtap="getSeatInfo">
 9         <text>點擊查看座位信息</text>
10     </view>
11     <view class="line"></view>
12 </block>
複製代碼

第一、11行很簡單,在站點與車次、車次與車次之間添加橫線。

當佈局中的組件個數和js中的數據有關,即在wxml中寫死組件不能知足需求時,能夠利用block和wx:for來進行組件的動態生成。

第2行wx:for="{{trainList}}"表示block塊中的組件可使用數組trainList中的內容,從下標0開始迭代,數據中有幾個元素,就會動態生成幾套組件。wx:for-item="train"指定數組中元素的名稱爲train(默認的是item,指定的意義之一是可讀性強),後續獲取屬性值時可經過train.key_name的形式。

第3行開始添加組件,類型是text,值爲{{index+1}}. 車次:{{train.trainNo}},前半部分用來標明每一個車次的序號,從1開始;而index和item相似,是默認的迭代索引名稱,其實就是數組元素當前的下標,從0開始。

後面幾行添加text組件和第3行差很少,但第8行有兩個點說一下:

*1 bindtap="getSeatInfo",綁定一個回調函數,點擊時跳轉到新頁面,顯示當前車次對應的座位信息;

*2 id="trainindex-{{index}}",給組件指定id,能夠看到以前的組件都沒有設置過該屬性(不須要就能夠不設置),那麼何時須要呢?其中一種狀況,當js中某組件綁定的回調方法須要得知是哪一個組件觸發了本身的時候,好比第一點中的方法getSeatInfo,要想點擊某車次的查看座位信息按鈕後顯示出對應的座位信息,就得知道點擊組件對應的trainList數組下標,而這個需求,正好能夠藉助id和index屬性來實現;

3.2.2 train.js

首先定義data成員trainList,用來接收index頁面傳遞過來的數據:

trainList: []

頁面啓動時如有數據須要載入,那麼得添加onLoad方法(一開始自動運行,在其中實現數據的加載與處理),不然能夠不添加。

複製代碼
1 onLoad: function(options) {
2   var jsonString = options.trainInfos;
3   //將字串類型轉爲JSON類型
4   var json = JSON.parse(jsonString);
5   this.setData({
6       trainList: json.data.trainList,
7   });
8 },
複製代碼

當方法的調用者有參數傳入時,咱們能夠經過添加方法參數的形式來獲取。對於參數名,自動啓方法通常爲options,組件回調方法通常爲e(event)。

第2行獲取index頁面在打開train頁面時傳入的火車票信息參數trainInfos。

第4行將String類型對象轉換回JSON格式,以前在index頁面提到過,url傳的參數是由JSON格式對象轉換過來的String類型。

第6行將真正的火車票車次信息數組取出,賦給數據成員trainList。

注意:給數據成員賦值時,必須調用頁面自身的setData方法,不然就算賦值了也不會同步到wxml文件中去,這一點容易出錯且很差定位緣由。

車次數組獲得後,wxml文件就會根據組件的屬性設置顯示對應的信息。再來看實現按鈕「點擊查看座位信息」對應的回調方法:

複製代碼
 1 getSeatInfo: function(e) {
 2     var prefix = 'trainindex-';
 3     var trainIndex = e.currentTarget.id.substring(prefix.length);
 4     //輸出根據組件id獲取的車票索引,用以顯示詳細的座位信息
 5     console.log(trainIndex);
 6     var trainNo = this.data.trainList[trainIndex].trainNo;
 7     var json = this.data.trainList[trainIndex].seatInfos;
 8     //將JSON類型轉爲String類型用以url參數傳遞,不然傳遞後會變成[object Object],同時傳遞車次
 9     var jsonString = JSON.stringify(json);
10     wx.navigateTo({
11         url: '../seat/seat?'+'trainNo='+trainNo+'&seatInfos='+jsonString,
12     });
13 },
複製代碼

第二、3行獲取以前定義的組件id中的index部分,即點擊組件對應的trainList數組的下標。固然原先定義時也能夠不添加前綴'trainindex-',徹底是爲了可讀性,由於當項目愈來愈大時有個一目瞭然的標示老是不錯的。

第六、7行分別獲取車次信息的列車號與座位信息,他們稍候會被傳遞到seat頁面。

第9行一樣地將獲得的JSON格式對象先轉換爲String類型,讓其能夠在url中做爲可被正確傳遞的參數。

第11行打開新的頁面seat顯示座位信息,多個參數之間以「&」符號分隔。

3.2.3 train.json

主程序中app.json文件除了配置須要調用onLoad方法的頁面外,還指定了一些全局的window樣式。若某個頁面在本身的json文件中沒有定義局部的window屬性,或根本沒有json文件,那默認將使用全局的。

項目初始沒有爲index生成json文件,由於其做爲啓動頁,直接用全局的「WeChat」就好,其實index標題應該是小程序的名稱,咱們本身真正開發的程序確定得取另外一個名字。

能夠看到,logs、train及seat都對標題進行了定義,結果就是會覆蓋掉全局的值。以train爲例,其在json文件中定義標題爲「站-站火車查詢信息」:

1 {
2   "navigationBarTitleText": "站-站火車查詢信息"
3 }

還有一點,頁面的json文件不須要也不能頁面配置屬性(Pages),只能設置window屬性,因此就能夠省略window名稱,直接像上述代碼用{...}形式便可。

 

3.3 seat

seat頁面用來顯示某車次的座位信息,包括座位等級、票價及餘票。經過train頁面的分析,相信你們對網絡請求,數據在頁面與頁面、wxml與js文件之間的傳遞漸漸熟悉了。而seat和train相似,沒有什麼特別的地方,因此和logs同樣這裏就再也不講什麼了。

 

 

4. 小感悟

 微信小程序,雖然目前還不知道其在微信的接入口,但應該和訂閱號、服務號以及企業號會有所不一樣。搜索打開使用,用完關閉,沒有移動app的安裝、下載等過程,微信流量大,輕便、易用等特性是其優勢。然而正是由於這個優勢,開發者擔憂這有可能使得小程序不可以像app那樣強大,畢竟接入口、審覈機制、推廣成本以及最大容許內存等這些還未肯定的因素對一款應用來講都是相當重要的。

對於初學者(如原先搞android開發),暫且無論上面提到的那些,在弄明白應用需求的同時,得邁開並加快對前端知識學習的腳步了。

相關文章
相關標籤/搜索