2008年12月29日

Ext各種表格製作

無論是界面之美,還是功能之強,ext的表格控件都高居榜首。



單選行,多選行,高亮顯示選中的行,推拽改變列寬度,按列排序,這些基本功能咱們就不提了。



自動生成行號,支持checkbox全選,動態選擇顯示哪些列,支持本地以及遠程分頁,可以對單元格按照自己的想法進行渲染,這些也算可以想到的功能。



再加上可編輯grid,添加新行,刪除一或多行,提示髒數據,推拽改變grid大小,grid之間推拽一或多行,甚至可以在tree和grid之間進行拖拽,啊,這些功能實在太神奇了。更令人驚嘆的是,這些功能竟然都在ext表格控件裡實現了。



呵呵~不過ext也不是萬能的,與fins的ecside比較,ext不能鎖定列(土豆說1.x裡支持鎖定列,但是2.0里沒有了,因為影響效率。),也沒有默認的統計功能,也不支持excel,pdf等導出數據。另外fins說,通過測試ecside的效率明顯優於ext呢。:)

2.2. 讓我們搞一個grid出來耍耍吧。





光說不練不是我們的傳統,讓我們基於examples裡的例子,來自己搞一個grid看看效果,同時也可以知道一個grid到底需要配置些什麼東西。



1.



首先我們知道表格肯定是二維的,橫著叫行,豎著叫列。跟設計數據庫,新建表一樣,我們要先設置這個表有幾列,每列叫啥名字,啥類型,咋顯示,這個表格的骨架也就出來了。



ext裡,這個列的定義,叫做ColumnModel,簡稱cm的就是它,它作為整個表格的列模型,是要首先建立起來的。



這裡我們建立一個三列的表格,第一列叫編號(code),第二列叫名稱(name),第三列叫描述(descn)。



var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



看到了吧?非常簡單的定義了三列,每列的header表示這列的名稱,dataIndex是跟後面的東西對應的,咱們暫且不提。現在只要知道有了三列就可以了。

2.



有了表格的骨架,現在我們要向裡邊添加數據了。這個數據當然也是二維了,為了簡便,我們學習examples裡的array-grid.js裡的方式,把數據直接寫到js裡。



var data = [

['1','name1','descn1'],

['2','name2','descn2'],

['3','name3','descn3'],

['4','name4','descn4'],

['5','name5','descn5']

];



很顯然,我們這裡定義了一個二維數據, (什麼?你不知道這是二維數組?快改行吧,這裡不是你該待的地方。)



這個有五條記錄的二維數組,顯示到grid裡就應該是五行,每行三列,正好對應這id,name,descn,在我們的腦子裡應該可以想像出grid顯示的結果了,為了讓想像變成顯示,我們還需要對原始數據做一下轉化。

3.



因為咱們希望grid不只能支持array,還可以支持json,支持xml,甚至支持咱們自己定義的數據格式,ext為咱們提供了一個橋樑,Ext.data.Store,通過它我們可以把任何格式的數據轉化成grid可以使用的形式,這樣就不需要為每種數據格式寫一個grid的實現了。現在咱們就來看看這個Ext.data.Store是如何轉換array的。



var ds = new Ext.data.Store({

proxy: new Ext.data.MemoryProxy(data),

reader: new Ext.data.ArrayReader({}, [

{name: 'id'},

{name: 'name'},

{name: 'descn'}

])

});

ds.load();



ds要對應兩個部分:proxy和reader。proxy告訴我們從哪裡獲得數據,reader告訴我們如何解析這個數據。



現在我們用的是Ext.data.MemoryProxy,它是專門用來解析js變量的。你可以看到,我們直接把data作為參數傳遞進去了。



Ext.data.ArrayReader專門用來解析數組,並且告訴我們它會按照定義的規範進行解析,每行讀取三個數據,第一個叫id,第二個叫 name,第三個descn。是不是有些眼熟,翻到前面cm定義的地方,哦,原來跟dataIndex是對應的。這樣cm就知道哪列應該顯示那條數據了。唉,你要是能看明白這一點,那你實在是太聰明了。



記得要執行一次ds.load(),對數據進行初始化。



有兄弟可能要問了,要是我第一列數據不是id而是name,第二列數據不是name而是id咋辦?嗯,嗯,這個使用就用mapping來解決。改改變成這樣:



var ds = new Ext.data.Store({

proxy: new Ext.data.MemoryProxy(data),

reader: new Ext.data.ArrayReader({}, [

{name: 'id', mapping: 1},

{name: 'name', mapping: 0},

{name: 'descn', mapping: 2}

])

});







這樣如截圖所見,id和name兩列的數據翻轉了。如此這般,無論數據排列順序如何,我們都可以使用mapping來控制對應關係,唯一需要注意的是,索引是從0開始的,所以對應第一列要寫成mapping:0,以此類推。

4.



哈哈,萬事俱備只欠東風,表格的列模型定義好了,原始數據和數據的轉換都做好了,剩下的只需要裝配在一起,我們的grid就出來了。



var grid = new Ext.grid.Grid('grid', {

ds: ds,

cm: cm

});

grid.render();



注意:上頭是ext-1.x的寫法,Ext.grid.Grid的第一個參數是渲染的id,對應在html裡應該有一個 <div id="grid"></div>的東西,這樣grid才知道要把自己畫到哪裡。



創建完grid以後,還要用grid.render()方法,讓grid開始渲染,這樣才能顯示出來。

5.



好了,把所有代碼組合到一起,看看效果吧。



var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



var data = [

['1','name1','descn1'],

['2','name2','descn2'],

['3','name3','descn3'],

['4','name4','descn4'],

['5','name5','descn5']

];



var ds = new Ext.data.Store({

proxy: new Ext.data.MemoryProxy(data),

reader: new Ext.data.ArrayReader({}, [

{name: 'id'},

{name: 'name'},

{name: 'descn'}

])

});

ds.load();



var grid = new Ext.grid.Grid('grid', {

ds: ds,

cm: cm

});

grid.render();



看看吧,這就是咱們搞出來的grid了。





html例子是lingo-sample/1.1.1目錄下的02-01.html,把這個目錄copy到ext-1.x的example目錄下,就可以直接打開觀看效果。

2.3. 上邊那個是1.x的,2.0稍微有些不同哦





首先,Ext.grid.Grid已經不見了,咱們需要用Ext.grid.GridPanel。需要傳遞的參數也有少許區別。



var grid = new Ext.grid.GridPanel({

el: 'grid',

ds: ds,

cm: cm

});



看到了嗎?負責指定渲染位置的id放到了{}裡邊,對應的名字是el。似乎ext2里對這些參數進行了統一,比以前更整齊了。



因為其他地方都一樣,我就不多說了,html例子在是lingo-sample/2.0目錄下的02-01.html。





從截圖上看,少了斑馬條,下邊多了一條線,應該只是css有所不同吧。



默認情況下,兩個版本的grid都可以拖拽列,也可以改變列的寬度。不知道怎麼禁用這兩個功能呢。







最大的不同應該是1.x裡默認支持的右鍵效果,在2.0里不見了。





按shift和ctrl多選行的功能倒是都有。區別是,全選後,1.x必須按住ctrl才能取消,直接單擊其中一個行,不會取消全選功能,而2.0里只需要任意點擊一行,就取消全選,只選中剛才點擊的那行。







哦,哦,那顏色不要也算是區別吧。

2.4. 按順序,咱們先要把常見功能講到,讓grid支持按列排序





其實很簡單,需要小小改動一下列模型。



var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id',sortable:true},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



如果你英語還可以,或者懂得查字典的話(軟件翻譯也算),那麼你就會知道,多出來的這個sortable屬性應該是可以排序的意思。現在咱們試一下改動後的效果。







看到了沒有?編號的標題上有個小小的箭頭,表格里的數據也是按照編號做的逆序排列,如此簡單,我們就實現了按列排序。



很有趣的是,2.0加上sortable以後,1.x那種右鍵功能也跑回來了,不過它用的不是右鍵,而是下拉菜單似的實現方式。





什麼?你問為什麼其他兩列無法排序?!嗯,好像是因為你還沒有給另兩列添加sortable屬性。



怎麼加?!按編號那樣加就行了。



還是不會?!-_-。



var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id',sortable:true},

{header:'名稱',dataIndex:'name',sortable:true},

{header:'描述',dataIndex:'descn',sortable:true}

]);



這樣所有列都可以排序了。什麼?怎麼取消排序?!-_-。

2.5. 讓單元格里顯示紅色的字,圖片,按鈕,你還能想到什麼?





嘿,希望你跟我一樣,不願意只能在grid裡看到文字,至少不是單調的,毫無特色的文字。有些人就問了,如果我想改變一下單元格里顯示內容,應該怎麼辦呢?



非常不幸的是,ext的作者,偉大的jack早已經想到了,說真的,你沒想到的,他都想到了,不只想到了,他還做出來了。



唉,這就是區別啊。為啥你就不能動手做些東西呢?就知道向別人要這要那,唉。



首先,我宣佈,偶們的數據要擴充啦,每個人要加上一個性別字段。



var data = [

['1','male','name1','descn1'],

['2','female','name2','descn2'],

['3','male','name3','descn3'],

['4','female','name4','descn4'],

['5','male','name5','descn5']

];



男女搭配,幹活不累撒。而且現在中國就是男多女少,我就還沒對象呢。徵婚中,單身女性加(QQ)771490531詳談。



你可以試試不改其他的部分,顯示的結果是不會改變的,因為原始數據要經過ds的處理才能被grid使用,那麼下一步我們就開始修改ds,把性別加進去。



var ds = new Ext.data.Store({

proxy: new Ext.data.MemoryProxy(data),

reader: new Ext.data.ArrayReader({}, [

{name: 'id'},

{name: 'sex'},

{name: 'name'},

{name: 'descn'}

])

});



添加了一行{name: 'sex'},把數組的第二列映射為性別。現在grid可以感覺到sex了,嘿嘿。



不過grid還顯示不了性別這列,因為咱們還沒改cm。



var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



到現在其實都沒什麼新東西,但是你不覺得光看平板字,很難分出哪個是GG哪個是MM嗎?聽說過紅男綠女沒?要是男的都加上紅色,女的都變成綠色,那不是清楚多了。就像下面一樣。





怎麼樣?是不是效果大不同了。你不會認為很難吧,嗯,確實,如果你對html和css完全搞不明白的話,勸你還是先去學學吧,對自己有信心的往下看。



var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex',renderer:function(value){

if (value == 'male') {

return "<span style='color:red;font-weight:bold;'>紅男</span>";

} else {

return "<span style='color:green;font-weight:bold;'>綠女</span>";

}

}},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



別被嚇到,這麼一大段其實就是判斷是男是女,然後配上顏色。你要是覺得亂,也可以這麼做。



function renderSex(value) {

if (value == 'male') {

return "<span style='color:red;font-weight:bold;'>紅男</span>";

} else {

return "<span style='color:green;font-weight:bold;'>綠女</span>";

}

}

var cm = new Ext.grid.ColumnModel([

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex',renderer:renderSex},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



實際上這個renderer屬性至關重要,它的值是一個function,哦,你說不知道js裡function可以這麼用?那麼恭喜你,現在你知道了。



renderer會傳遞個參數進去,咱們grid裡看到的,是這個函數的返回值,怎麼樣,神奇吧?



同志們,你們也應該看到了,返回html就可以,是html啊,html裡有的東西,你返回什麼就顯示什麼,顏色,鏈接,圖片,按鈕,只要你願意,整個網頁都可以返回回去。還有什麼做不到的?哦,你不會html,那沒轍,回去學吧。



咱們先來個圖片。





function renderSex(value) {

if (value == 'male') {

return "<span style='color:red;font-weight:bold;'>紅男</span><img src='user_male.png' />";

} else {

return "<span style='color:green;font-weight:bold;'>綠女</span><img src='user_female.png' />";

}

}



是不是太簡單了,下面咱們來玩點兒高級的。



function renderDescn(value, cellmeta, record, rowIndex, columnIndex, store) {

var str = "<input type='button' value='查看詳細信息' onclick='alert(\"" +

"這個單元格的值是:" + value + "\\n" +

"這個單元格的配置是:{cellId:" + cellmeta.cellId + ",id:" + cellmeta.id + ",css:" + cellmeta.css + "}\\n" +

"這個單元格對應行的record是:" + record + ",一行的數據都在裡邊\\n" +

"這是第" + rowIndex + "行\\n" +

"這是第" + columnIndex + "列\\n" +

"這個表格對應的Ext.data.Store在這裡:" + store + ",隨便用吧。" +

"\")'>";

return str;

}



來看看我們可以在render裡用到多少參數:



1.



value是當前單元格的值

2.



cellmeta裡保存的是cellId單元格id,id不知道是干啥的,似乎是列號,css是這個單元格的css樣式。

3.



record是這行的所有數據,你想要什麼,record.data["id"]這樣就獲得了。

4.



rowIndex是行號,不是從頭往下數的意思,而是計算了分頁以後的結果。

5.



columnIndex列號太簡單了。

6.



store,這個厲害,實際上這個是你構造表格時候傳遞的ds,也就是說表格里所有的數據,你都可以隨便調用,唉,太厲害了。



有個同學就問啦:EXT render的參數,是如何得到的呢。因為你講的那些都是EXT自己內部的。它是如何把這些參數傳遞給render的呢?



這個問題其實比較簡單,只是你們想複雜了。既然是函數,就肯定有調用它的地方,你找到GridView.js在裡邊搜索一下renderer,就會看到調用render的地方,這些參數都是在這裡傳進去的。



好,看看效果吧。





剩下的,就是發揮各位聰明才智的時候了,舞台已經搭好,看你如何表演了。



html例子,1.x版本在lingo-sample/1.1.1目錄下的02-02.html,2.0的版本在lingo-sample/2.0目錄下的02-02.html。

2.6. 更進一步,自動行號和多選checkbox





實際上行號和多選checkbox都是renderer的延伸,當然多選checkbox更酷一點兒,兩者經常一起使用,所以讓我們放在一起討論好了。

2.6.1. 自動行號





只需要在cm中加上一行,這一行不會與ds中的任何數據對應,這也告訴我們可以憑空製作列,哈哈。



在之前的例子上改啦。



var cm = new Ext.grid.ColumnModel([

{header:'NO.',renderer:function(value, cellmeta, record, rowIndex){

return rowIndex + 1;

}},

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



如吾等所願,不指定dataIndex,而是直接根據renderer返回rowIndex + 1,因為它是從0開始的,所以加個一。截圖如下。





1.x的例子在lingo-sample/1.1.1/02-03.html



很遺憾的是,2.0里有自己的默認實現了,咱們不能展現自己的手工技藝了,還是乖乖使用jack提供的東東吧。



於是,在2.0里cm就變成了這幅模樣。



var cm = new Ext.grid.ColumnModel([

new Ext.grid.RowNumberer(),

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



你絕對會同意我的意見,Jack's work is amazing.實在是太神奇了。看看截圖就知道。





2.0的例子在lingo-sample/2.0/02-03.html

2.6.2. 全選checkbox的時間了,請允許我讓2.0先上場。





因為2.0里有checkboxSelectionModel,這樣完全可以證實用別人的輪子,比自己造輪子要方便。而且咱們造的輪子完全沒有jack圓。不信的話,看下面1.x裡的實現。



我們一直在修改cm,這次我們也要對它動刀了,不過SelectionModel既sm也要處理一下,這是為了改變單選和多選行的方式,以前這些可以靠shift或ctrl實現,而現在這些都要與checkbox關聯上了。



啦啦啦,先看圖片,後看代碼。





先看看具體多了什麼



var sm = new Ext.grid.CheckboxSelectionModel();



神奇的是這個sm身兼兩職,使用的時候既要放到cm裡,也要放到grid中。代碼如下。



var cm = new Ext.grid.ColumnModel([

new Ext.grid.RowNumberer(),

sm,

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);



var grid = new Ext.grid.GridPanel({

el: 'grid',

ds: ds,

cm: cm,

sm: sm

});



然後你就可以得到效果啦,代碼在lingo-sample/2.0/02-04.html。

2.6.3. 1.x時代的全選checkbox。





理論上只需要給cm再加一列,像自動編號那樣,不對應數據,只顯示checkbox就可以了。難點就是checkbox與某一行被選擇的時候要對應上,用checkbox選擇上,sm裡也要讓這一行被選中,反之亦然。嗯,估計會比較複雜呢。



先放上顯示checkbox的代碼和截圖:



var cm = new Ext.grid.ColumnModel([

{header:'NO.',renderer:function(value, cellmeta, record, rowIndex){

return rowIndex + 1;

}},

{header:'<input type="checkbox" onclick="selectAll(this)">',renderer:function(value, cellmeta, record, rowIndex){

return '<input type="checkbox" name="cb">';

}},

{header:'編號',dataIndex:'id'},

{header:'性別',dataIndex:'sex'},

{header:'名稱',dataIndex:'name'},

{header:'描述',dataIndex:'descn'}

]);







與sm對接的方面比較麻煩,好在extjs.com上已經有擴展了,或者你可以看看我們弄下來的。 看看1.x多選樹的截圖。

2.7. 分頁了嗎?分頁了嗎?如果還沒分就看這裡吧。





如果你有一千條信息,一次都輸出到grid裡,然後讓客戶用下拉條一點兒一點兒去找吧。我們這裡可是要做一個分頁效果了,不用滾動屏幕,或者滾動一下就可以看到本頁顯示的數據,如果想看其他的只需要翻頁就可以了。同志們,加強客戶體驗呀。



實際上,grid控件挺耗性能的,據土豆講一個頁面上放3個grid就可以感覺到響應變慢,以前看過介紹,grid裡顯示數據過多,聽說是上千條,也會明顯變慢。



所以說分頁是必不可少滴,而且jack提供了方便集成分頁工具條的方式,不用一下實在是太浪費了。



兩步走,讓grid集成分頁。

2.7.1. 表面工作,先把分頁工具條弄出來。







從圖片可以清晰的看到,在grid下邊多出來一行東東,包括了前一頁,後一頁,第一頁,最後一頁,刷新,以及提示信息。而我們不過寫了如下幾行代碼而已,神奇呀。



var gridFoot = grid.getView().getFooterPanel(true);



var paging = new Ext.PagingToolbar(gridFoot, ds, {

pageSize: 10,

displayInfo: true,

displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',

emptyMsg: '沒有記錄'

});



首先使用grid.getView().getFootPanel(true),獲得grid下邊那一條,嘿嘿,人家grid就設計的這麼好,腳底下專門留了地方讓你放東西。我們老實不客氣,把Ext.PagingToolbar放到上邊,就可以顯示分頁工具條了。



這分頁工具條可不是個擺設,你按了前一頁,後一頁,整個grid都要有反應才對,要不咱們費勁弄這個麼東西過來幹嘛呀?所以,我們在構造 PagingToolbar的時候,不但告訴它,在gridFoot上顯示,還告訴它,進行分頁跳轉的時候,要對ds也進行操作。這個ds就是grid用來獲取和顯示數據的,它一變整個grid都發生變化,嘿嘿~這就算共享數據模型了。厲害呀。



知道了分頁的玄機,讓我們揉揉眼睛,好好看看裡邊的參數。



1.



pageSize,是每頁顯示幾條數據。

2.



displayInfo,跟下面的配置有關,如果是false就不會顯示提示信息。

3.



displayMsg,只有在displayInfo:true的時候才有效,用來顯示有數據的時候的提示信息,中國人應該看得懂漢語,到時候{0},{1},{2}會自動變成對應的數據,咱們只需要想辦法把話說通就行了。

4.



emptyMsg,要是沒數據就顯示這個,jack實在太貼心了,連這些小處都考慮得如此精細。



最好要注意的是,這段代碼必須放在grid.render()之後,估計是因為動態生成grid的dom後,才能獲得對應的footPanel。



現在給出例子,1.x的例子在lingo-sample/1.1.1/02-05.html。

2.7.2. 2.0賜予我們更大的靈活性





其實,在下,一直,對於:必須先渲染grid才能獲得footPanel這事非常憤恨,你想啊,本來分頁也應該屬於初始化的一部分,現在卻要先初始化grid,配置完畢,渲染,回過頭來再從grid裡把footPanel拿出來,再咕噥分頁的配置。真,真,真鬱悶呀。



所以2.0里的方式,簡直大快民心。



var grid = new Ext.grid.GridPanel({

el: 'grid',

ds: ds,

cm: cm,

bbar: new Ext.PagingToolbar({

pageSize: 10,

store: ds,

displayInfo: true,

displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',

emptyMsg: "沒有記錄"

})

});

ds.load();



嘿嘿,加一個bbar的參數就可以了,bbar就是bottom bar啦,底端工具條。





不過還是要注意一點,與1.x中不同的是,如果配置了分頁工具條,ds.load()就必須在構造grid以後才能執行,否則分頁工具條會不起作用。看來分頁工具條會把自己和ds做一些關聯,來完成與grid共享數據模型的。



對了,還有一點不同,1.x中分頁條不會隨著瀏覽器的大小改變,自動放縮,這點在2.0中也解決了。



2.0的例子在lingo-sample/2.0/02-05.html。

2.7.3. 迫不得已,要加上後台腳本了。





grid會每次都顯示ds中所有的數據,咱們沒法利用靜態數據好好演示分頁,於是,必須寫後台腳本,讓ext與後台進行數據交互才能看到真實的分頁效果。



咱們儘量在原來的基礎上修改啊,把注意力集中在關鍵部位,一次性突破。



我不會其他語言,後台就用jsp寫啦。有個好消息是只要返回的數據格式一樣,ext才不管後台是什麼寫的呢。也就是這樣,不管你以後用什麼實現後台,前台的ext代碼都一樣。



<%

String start = request.getParameter("start");

String limit = request.getParameter("limit");

try {

int index = Integer.parseInt(start);

int pageSize = Integer.parseInt(limit);



String json = "{totalProperty:100,root:[";

for (int i = index; i < pageSize + index; i++) {

json += "{id:" + i + ",name:'name" + i + "',descn:'descn" + i + "'}";

if (i != pageSize + index - 1) {

json += ",";

}

}

json += "]}";

response.getWriter().write(json);

} catch(Exception ex) {

}

%>



下面我們來解讀這段jsp代碼:



1.



在進行操作之前,我們先要獲得ext傳遞過來的兩個參數:start和limit,start指的從第幾個數據開始顯示,limit是說從start開始,一共要用多少個數據,當然返回的數據可能會小於這個值。

2.



咱們在後台模擬對100條數據進行分頁,在獲得了start和limit之後再生成json格式的數據。



何謂json?在理論講解之前先看看實例,讓我們能有個感性認識,至於以後能不能昇華到理性認識,就看各位的悟性了。



模擬ext訪問後台,並傳遞兩個參數start=0&limit=10,把獲得的數據稍微整理一下,是這個樣子。



{totalProperty:100,root:[

{id:0,name:'name0',descn:'descn0'},

{id:1,name:'name1',descn:'descn1'},

{id:2,name:'name2',descn:'descn2'},

{id:3,name:'name3',descn:'descn3'},

{id:4,name:'name4',descn:'descn4'},

{id:5,name:'name5',descn:'descn5'},

{id:6,name:'name6',descn:'descn6'},

{id:7,name:'name7',descn:'descn7'},

{id:8,name:'name8',descn:'descn8'},

{id:9,name:'name9',descn:'descn9'}

]}



請記住這個數據格式,不管後台是什麼,只要滿足了這樣的格式要求,ext就可以接收處理,顯示到grid中。



我這裡就不好好介紹json,現在只需要知道json裡頭除了name(名稱)就是value(值),值有好幾種格式,如果是數字就不用加引號,如果加了引號就是字符串,如果用[]包裹就是數組,如果出現{}就說明是嵌套的json。諸如此類。



簡單瞄了json一眼,開頭就是totalProperty:100,這告訴ext:「俺這裡有100個數據呢。」,然後就是root: [],root對應著一個數組,數組裡有10個對象,每個對象都有id呀,name呀,descn呀。這10個數據最後就應該顯示到表格里。

3.



jsp裡用for循環生成root數組裡的數據,這樣我們翻頁的時候可以看到數據的變化,要不每次都是一樣的數據,你怎麼知道翻頁是不是起作用了呢?



最後我們把得到的json字符串輸出到response裡,ext也就可以獲得這些數據了。



結果經過了一番折騰,我們的jsp已經確定可以返回我們所需要的數據了。現在我們可以忘掉後台是用什麼語言寫的了,直接切入ext代碼,看看它是怎麼樣才能跑去後台獲得這些數據呢?



因為引入了json作為數據傳輸格式,這次我們要對ext代碼進行一次大換血了,請做好思想準備。



1.



換掉proxy,別在內存裡找了,讓我們通過http獲得我們想要的。



proxy: new Ext.data.HttpProxy({url:'grid.jsp'}),



創建HttpProxy的同時,用url這個參數指定咱們去哪裡取數據,我們這裡設置成grid.jsp,就是我們剛才討論的jsp腳本啦。

2.



已經不是數組了,現在要用json咯。



reader: new Ext.data.JsonReader({

totalProperty: 'totalProperty',

root: 'root'

}, [

{name: 'id'},

{name: 'name'},

{name: 'descn'}

])



看比ArrayReader多了什麼?totalProperty對應咱們jsp返回的totalProperty,也就是數據的總數。root對應咱們jsp返回的root,就是一個包含返回數據的數組。

3.



好了,最後在初始化的時候,告訴我們希望獲得哪部分的數據就可以了。



ds.load({params:{start:0,limit:10}});



就在ds讀取的時候添加兩個參數,start和limit,告訴後台,我們從第一個數可以取起,最多要10個。



在這裡有一個小插曲,如果你按照我們以前的設置,grid是無法正常顯示的,因為ds.load()無法在grid.render()前準備好所有數組,所以它不知道自己應該實現多高。沒法子,我們只好為它指定一個固定的高度了。像這樣<div id="grid" style="height:265px;"></div>。



最後,我們就可以使用分頁條上那些按鈕試試分頁了。呵呵~就這麼簡單。



1.x的例子在lingo-sample/1.1.1/02-06.html,jsp文件在lingo-sample/1.1.1/grid.jsp,下面是它的截圖:





有趣的是,1.x中,不需要為div指定高度,它自己就知道如何顯示,不曉得為什麼2.0里不這樣做呢。



2.0的例子在lingo-sample/2.0/02-06.html,jsp文件在lingo-sample/2.0/grid.jsp,下面是它的截圖:



2.7.4. 其實分頁不一定要踩在腳下,也可以頂在頭上。





我的意思是,grid除了FootPanel以外,還有HeaderPanel,意思就是頭頂上的面板。我們把分頁條放在上面也不會有任何問題。1.x中的代碼僅僅是將getFooterPanel改成getHeaderPanel,這樣分頁條就跑到上頭去了。



var gridHead = grid.getView().getHeaderPanel(true);



var paging = new Ext.PagingToolbar(gridHead, ds, {

pageSize: 10,

displayInfo: true,

displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',

emptyMsg: '沒有記錄'

});







1.x的例子可以在lingo-sample/1.1.1/02-07.html找到。



2.0就更簡單了,只需要改一個字母,b -> t,呵呵~,讓原來的bbar(bottom bar)變成tbar(top bar)就可以讓我們的工具條登天了。



var grid = new Ext.grid.GridPanel({

el: 'grid',

ds: ds,

cm: cm,

tbar: new Ext.PagingToolbar({

pageSize: 10,

store: ds,

displayInfo: true,

displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',

emptyMsg: "沒有記錄"

})

});