ExtJs的Grid元件雖然不管從哪一方面來講,都稱得上是很好很強大,但是總會有一些應用場景并不需要這麼多功能,比如網站的留言清單,開發者隻想要一個簡單的<li>或<table>清單而已,這時候XTemplate就顯得很有用了。
本文将講解如何用XTemplate結合WCF與服務端互動,生成資料清單,同時加上無重新整理分頁功能(預設情況下ExtJs并沒有為XTemplate并沒有提供分頁功能)
1.先做一些準備工作,寫一個通用的類(改編自老張的PageData),用于WCF向ExtJs傳回分頁資料
2.DateTime序列化問題,因為.net序列化DateTime時,不管你怎麼努力,隻要是DateTime類型,最終隻能生成類似 "F_Date":"\/Date(1221023588109+0800)\/"這樣的字元串,ExtJs并不能正确識别!為此我們需要一個第三方的用于序列化DateTime的小工具Newtonsoft.Json.dll,它是專門用于将對象序列化成Json字元串。重要的是,用這個序列化後的DateTime字元串,ExtJs能夠識别(注:百度搜尋一下"Newtonsoft.Json"很容易就能找到N多下載下傳的,下載下傳後直接添加到項目引用裡即可)
3.編寫具體的實體類T_GuestBook,直接在資料庫裡建好,拖到dbml裡就可以了,主要代碼如下(注意要設定dbml的序列化屬性為"單向",否則vs不會自動為class以及成員加上序列化标簽):
為閱讀友善,去掉了一些自動生成的代碼
4.建一個WCF服務,并添加一個方法:
注意,這裡我們傳回的是string類型,并且是用JavaScriptConvert.SerializeObject處理後的JSON字元串,至于WebInvoke(ResponseFormat = WebMessageFormat.Json這裡為什麼要加Json傳回格式,原因很簡單,不指定Json格式,預設就是以xml傳回的,會無端在前後加上更多無用字元
5.ExtJs前端完整代碼:
這裡有幾個要點:
(1).datetime在xtemplate中的格式化寫法:{F_Date:date("Y-m-d H:i:s")}
(2).服務端傳回字元格式的處理:
因為JavaScriptConvert.SerializeObject(_PageData)這裡已經成功序列化了,但是wcf的服務在傳回時,必須要有一種格式,要麼xml,要麼json,是以我們指定了wcf以json格式傳回後,會對正常的結果再做一次序列化,最後的結果是使字元串前後都加上了雙引号,同時把原來正常的雙引号做了轉義處理,參考下面的:
正常的Json字元串:
{"RecordCount":6,"PageSize":3,"PageCount":2,"CurrentPageIndex":1,"Data":[{"F_ID":1,"F_IP":"192.23.37.41","F_Date":new Date(1221052494578),"F_Content":"這是第一條留言","F_Reply":""},{"F_ID":2,"F_IP":"192.168.0.1","F_Date":new Date(1221052494578),"F_Content":"這是第二條留言","F_Reply":""},{"F_ID":3,"F_IP":"192.168.0.2","F_Date":new Date(1221052494578),"F_Content":"這是第三條留言","F_Reply":""}]}
伺服器傳回的Json字元串:
"{\"RecordCount\":6,\"PageSize\":3,\"PageCount\":2,\"CurrentPageIndex\":1,\"Data\":[{\"F_ID\":1,\"F_IP\":\"192.23.37.41\",\"F_Date\":new Date(1221052494578),\"F_Content\":\"這是第一條留言\",\"F_Reply\":\"\"},{\"F_ID\":2,\"F_IP\":\"192.168.0.1\",\"F_Date\":new Date(1221052494578),\"F_Content\":\"這是第二條留言\",\"F_Reply\":\"\"},{\"F_ID\":3,\"F_IP\":\"192.168.0.2\",\"F_Date\":new Date(1221052494578),\"F_Content\":\"這是第三條留言\",\"F_Reply\":\"\"}]}"
是以我們要處理一下,關鍵代碼:
//轉換伺服器端傳回字元串的格式
var data = request.responseText;
data = data.substr(1);
data = data.substr(0, data.length - 1);
data = data.replace(/\\\"/g, '"');
data = Ext.util.JSON.decode(data)
(3).為使分頁按鈕有效,我們需要在成功傳回服務端資料後,為每個分頁連結以及按鈕加上onClick事件,即這一部分
//開始處理分頁按鈕/連結事件
var oBtnGo = Ext.get("btnGo");
var oGoPage = Ext.get("GoPage");
oBtnGo.on("click", function() {
loadData(iPageSize, oGoPage.dom.value);
});
var oBtnFirst = Ext.get("btnFirst"); //第一頁
oBtnFirst.on("click", function() { loadData(iPageSize, 1); })
var oBtnPre = Ext.get("btnPre"); //上一頁
oBtnPre.on("click", function() { loadData(iPageSize, iCurrentPageIndex - 1); })
var oBtnNext = Ext.get("btnNext"); //下一頁
oBtnNext.on("click", function() { loadData(iPageSize, iCurrentPageIndex + 1); })
var oBtnLast = Ext.get("btnLast"); //最後一頁
oBtnLast.on("click", function() { loadData(iPageSize, iPageCount); })
另外這一段代碼的位置,也要留意一下,不能寫在其它地方:比如Ajax請求之後,因為當Ajax還未成功傳回資料/XTemplate未成功更新時,分頁按鈕以及連結還沒有加載到頁面中,這時如果用Ext.get()取對象,Js會報錯
完成了,我們來看下一效果:
最後講一點題外話:
做完這個後,我在想:單就這個示例而言,這跟直接用asp.net ajax的updatePannel有什麼差別,有什麼優勢呢?相信也有不少人跟我有一樣的疑問,後來我想了想,至少有二個好處:
a.updatepannel預設會引起大量的資料回發,雖然頁面沒重新整理,但是用戶端跟服務端之間的傳輸資料量很大,而用ExtJs+Wcf,除了wcf傳回的字元串,就沒其它東西了,性能上會提高
b.相對而言,ExtJs的Ajax請求方式,我覺得比aspx.net ajax的更容易操作.