第二章、開(kāi)始ExtJS
2.1
獲得ExtJS
adapter:負責將里面提供第三方底層庫(包括Ext 自帶的底層庫)映射為Ext 所支持
的底層庫。
build: 壓縮后的ext 全部源碼(里面分類(lèi)存放)。
docs: API 幫助文檔。
exmaples:提供使用ExtJs 技術(shù)做出的小實(shí)例。
resources:Ext UI 資源文件目錄,如CSS、圖片文件都存放在這里面。
source: 無(wú)壓縮Ext 全部的源碼(里面分類(lèi)存放) 遵從Lesser GNU (LGPL) 開(kāi)源的
協(xié)議。
Ext-all.js:壓縮后的Ext 全部源碼。
ext-all-debug.js:無(wú)壓縮的Ext 全部的源碼(用于調試)。
ext-core.js:壓縮后的Ext 的核心組件,包括sources/core 下的所有類(lèi)。
ext-core-debug.js:無(wú)壓縮Ext 的核心組件,包括sources/core 下的所有類(lèi)。
2.2
應用ExtJS
應用extjs 需要在頁(yè)面中引入extjs 的樣式及extjs 庫文件,樣式文件為resources/css/extall.css,extjs 的js 庫文件主要包含兩個(gè),adapter/ext/ext-base.js 及ext-all.js,其中ext-base.js表示框架基礎庫,ext-all.js 是extjs 的核心庫。adapter 表示適配器,也就是說(shuō)可以有多種適配器,因此, 可以把adapter/ext/ext-base.js 換成adapter/jquery/ext-jquery-adapter.js , 或
adapter/prototype/ext-prototype-adapter.js 等。因此,要使用ExtJS 框架的頁(yè)面中一般包括下面幾句:
在ExtJS 庫文件及頁(yè)面內容加載完后,ExtJS 會(huì )執行Ext.onReady 中指定的函數,因此
可以用,一般情況下每一個(gè)用戶(hù)的ExtJS 應用都是從Ext.onReady 開(kāi)始的,
第三章Ext
框架基礎及核心簡(jiǎn)介
3.1
Ext
類(lèi)庫簡(jiǎn)介
ExtJS 由一系列的類(lèi)庫組成,一旦頁(yè)面成功加載了ExtJS 庫后,我們就可以在頁(yè)面中通
過(guò)javascript 調用ExtJS 的類(lèi)及控件來(lái)實(shí)現需要的功能。ExtJS 的類(lèi)庫由以下幾部分組成:
底層API(core):底層API 中提供了對DOM 操作、查詢(xún)的封裝、事件處理、DOM 查詢(xún)
器等基礎的功能。其它控件都是建立在這些底層api 的基礎上,底層api 位于源代碼目錄的
core 子目錄中,包括DomHelper.js、Element.js 等文件,如圖xx 所示。
控件(widgets):控件是指可以直接在頁(yè)面中創(chuàng )建的可視化組件,比如面板、選項板、
表格、樹(shù)、窗口、菜單、工具欄、按鈕等等,在我們的應用程序中可以直接通過(guò)應用這些控
件來(lái)實(shí)現友好、交互性強的應用程序的UI??丶挥谠创a目錄的widgets 子目錄中,包含
3.2
Ext的組件
Ext2.0 對框架進(jìn)行了非常大的重構,其中最重要的就是形成了一個(gè)結構及層次分明的組
件體系,由這些組件形成了Ext 的控件,Ext 組件是由Component 類(lèi)定義,每一種組件都有
一個(gè)指定的xtype 屬性值,通過(guò)該值可以得到一個(gè)組件的類(lèi)型或者是定義一個(gè)指定類(lèi)型的組
件。
組件大致可以分成三大類(lèi),即基本組件、工具欄組件、表單及元素組件。
基本組件有:
xtype Class
box Ext.BoxComponent 具有邊框屬性的組件
Button Ext.Button 按鈕
colorpalette Ext.ColorPalette 調色板
component Ext.Component 組件
container Ext.Container 容器
cycle Ext.CycleButton
dataview Ext.DataView 數據顯示視圖
datepicker Ext.DatePicker 日期選擇面板
editor Ext.Editor 編輯器
editorgrid Ext.grid.EditorGridPanel 可編輯的表格
3.3
組件的使用
組件可以直接通過(guò)new 關(guān)鍵子來(lái)創(chuàng )建,比如控件一個(gè)窗口,使用new Ext.Window(),
創(chuàng )建一個(gè)表格則使用new Ext.GridPanel()。當然,除了一些普通的組件以外,一般都會(huì )在構造函數中通過(guò)傳遞構造參數來(lái)創(chuàng )建組件。
組件的構造函數中一般都可以包含一個(gè)對象,這個(gè)對象包含創(chuàng )建組件所需要的配置屬性
及值,組件根據構造函數中的參數屬性值來(lái)初始化組件。比如下面的例子:
grid Ext.grid.GridPanel 表格
paging Ext.PagingToolbar 工具欄中的間隔
panel Ext.Panel 面板
progress Ext.ProgressBar 進(jìn)度條
splitbutton Ext.SplitButton 可分裂的按鈕
tabpanel Ext.TabPanel 選項面板
treepanel Ext.tree.TreePanel 樹(shù)
viewport Ext.ViewPort 視圖
window Ext.Window 窗口
工具欄組件有
toolbar Ext.Toolbar 工具欄
tbbutton Ext.Toolbar.Button 按鈕
tbfill Ext.Toolbar.Fill 文件
tbitem Ext.Toolbar.Item 工具條項目
tbseparator Ext.Toolbar.Separator 工具欄分隔符
tbspacer Ext.Toolbar.Spacer 工具欄空白
tbsplit Ext.Toolbar.SplitButton 工具欄分隔按鈕
tbtext Ext.Toolbar.TextItem 工具欄文本項
表單及字段組件包含
form Ext.FormPanel Form 面板
checkbox Ext.form.Checkbox checkbox 錄入框
combo Ext.form.ComboBox combo 選擇項
datefield Ext.form.DateField 日期選擇項
field Ext.form.Field 表單字段
fieldset Ext.form.FieldSet 表單字段組
hidden Ext.form.Hidden 表單隱藏域
htmleditor Ext.form.HtmlEditor html 編輯器
numberfield Ext.form.NumberField 數字編輯器
radio Ext.form.Radio 單選按鈕
textarea Ext.form.TextArea 區域文本框
textfield Ext.form.TextField 表單文本框
timefield Ext.form.TimeField 時(shí)間錄入項
trigger Ext.form.TriggerField 觸發(fā)錄入項
運行上面的代碼可以實(shí)現如下圖所示的結果:
可以省掉變量obj,直接寫(xiě)成如下的形式:
render 方法后面的參數表示頁(yè)面上的div 元素id,也可以直接在參數中通過(guò)renderTo 參
數來(lái)省略手動(dòng)讞用render 方法,只需要在構造函數的參數中添加一個(gè)renderTo 屬性即可,
如下:
對于容器中的子元素組件,都支持延遲加載的方式創(chuàng )建控件,此時(shí)可以直接通過(guò)在需要
父組件的構造函數中,通過(guò)給屬性items 傳遞數組方式實(shí)現構造。如下面的代碼:
注意中括號中加粗部份的代碼,這些代碼定義了TabPanel 這個(gè)容器控件中的子元素,
var obj={title:"hello",width:300,height:200,html:'Hello,easyjf open source'};
var panel=new Ext.Panel(obj); panel.render("hello");
<div id="hello"> </div>
var panel=new Ext.Panel({title:"hello",width:300,height:200,html:'<h1>Hello,easyjf open source</h1>'});
panel.render("hello");
New Ext.Panel({renderTo:"hello",title:"hello",width:300,height:200,html:'<h1>Hello,easyjf open source
</h1>'});
var panel=new Ext.TabPanel({width:300,height:200,items:[ {title:"面板1",height:30},{title:"面板
2",height:30},{title:"面板3",height:30}]});panel.render("hello");
這里包括三個(gè)面板。上面的代碼與下面的代碼等價(jià):
前者不但省略掉了new Ext.Panel 這個(gè)構造函數,最重要前者只有在初始化TabPanel 的
時(shí)候,才會(huì )創(chuàng )建子面板,而第二種方式則在程序一開(kāi)始就會(huì )創(chuàng )建子面板。也就是說(shuō),前者實(shí)
現的延遲加載。
3.4
組件的配置屬性
在ExtJS 中,除了一些特殊的組件或類(lèi)以外,所有的組件在初始化的時(shí)候都可以在構造
函數使用一個(gè)包含屬性名稱(chēng)及值的對象,該對象中的信息也就是指組件的配置屬性。
比如配置一個(gè)面板:
再比如創(chuàng )建一個(gè)按鈕:
var panel=new Ext.TabPanel({width:300,height:200,items:[new Ext.Panel( {title:"面板1",height:30}),new
Ext.Panel({title:"面板2",height:30}),new Ext.Panel({title:"面板3",height:30})]});panel.render("hello");
new Ext.Panel({
title:"面板",
html"面板內容",
height:100}
);
再比如創(chuàng )建一個(gè)Viewport 及其中的內容:
每一個(gè)組件除了繼承基類(lèi)中的配置屬性以外,還會(huì )根據需要增加自己的配置屬性,另外
子類(lèi)中有的時(shí)候還會(huì )把父類(lèi)的一些配置屬性的含義及用途重新定義。學(xué)習及使用ExtJS,
其中最關(guān)鍵的是掌握ExtJS 中的各個(gè)組件的配置屬性及具體的含義,這些配置屬性在下載下
來(lái)的ExtJS 源碼文檔中都有詳細的說(shuō)明,可以通過(guò)這個(gè)文檔詳細了解每一個(gè)組件的特性,
如下圖所示:
var b=new Ext.Button({
text:"添加",
pressed:true,
heigth:30,
handler:Ext.emptyFn
});
new Ext.Viewport({
layout:"border",
items:[{region:"north",
title:"面板",
html:"面板內容",
height:100},
{region:"center",
xtype:"grid",
title:"學(xué)生信息管理",
store:troe,
cm:colM,
store:store,
autoExpandColumn:3
}
]
});
由于所有的組件都繼承自Ext.Component,因此在這里我們列出組件基類(lèi)Component 中
的配置屬性簡(jiǎn)單介紹。
配置屬
性名稱(chēng)
類(lèi)型簡(jiǎn)介
allowDomMove
Boolean
當渲染這個(gè)組件時(shí)是否允許移動(dòng)Dom節點(diǎn)(默認值為true)。
applyTo
Mixed 混合參數,表示把該組件應用指定的對象。參數可以是—節點(diǎn)的id,
一個(gè)DOM節點(diǎn)或一個(gè)存在的元素或與之相對應的在document中已出現
的id。當使用applyTo,也可以提供一個(gè)id或CSS的class名稱(chēng),如果子組
件允許它將嘗試創(chuàng )建一個(gè)。如果指寫(xiě)applyTo選項,所有傳遞到renderTo
方法的值將被忽略,并且目標元素的父節點(diǎn)將自動(dòng)指定為這個(gè)組件的容
器。使用applyTo選項后,則不需要再調用render()方法來(lái)渲染組件。
autoShow
Boolean
自動(dòng)顯示,如為true,則組件將檢查所有隱藏類(lèi)型的class(如:’x-hidden’
或’x-hide-display’并在渲染時(shí)移除(默認為false)。
Cls
String 給組件添加額外的樣式信息,(默認值為''),如果想自定義組件或它的
子組件的樣式,這個(gè)選項是非常有用的。
ctCls
String 給組件的容器添加額外的樣式信息,默認值為'')。
disabled
Class
String 給被禁用的組件添加額外的CSS樣式信息,(默認為"x-item-disabled")。
hideMo
de
String 組件的隱藏方式, 支持的值有’visibility’ , 也就是css 里的
visibility,’offsets’負數偏移位置的值和’display’也就是css里的display,
默認值為’display’。
hideParent
Boolean
是否隱藏父容器,該值為true時(shí)將會(huì )顯示或隱藏組件的容器,false時(shí)則
只隱藏和顯示組件本身(默認值為false)。
id
String 組件的id,默認為一個(gè)自動(dòng)分配置的id。
listeners
Object 給對象配置多個(gè)事件監聽(tīng)器,在對象初始化會(huì )初始化這些監聽(tīng)器。
plugins
Object/ 一個(gè)對象或數組,將用于增加組件的自定義功能。一個(gè)有效的組件插
3.5
Extjs
組件的事件處理
ExtJS 提供了一套強大的事件處理機制,通過(guò)這些事件處理機制來(lái)響應用戶(hù)的動(dòng)作、監
控控件狀態(tài)變化、更新控件視圖信息、與服務(wù)器進(jìn)行交互等等。事件統一由
Ext.EventManager 對象管理,與瀏覽器W
Ext.EventObject 事件對象。支持事件處理的類(lèi)(或接口)為Ext.util.Observable,凡是繼承該類(lèi)的組件或類(lèi)都支持往對象中添加事件處理及響應功能。
首先我們來(lái)看標準html 中的事件處理,看下面的html 代碼:
Array 件必須包含一個(gè)init方法,該方法可以帶一個(gè)Ext.Component類(lèi)型參數。
當組件建立后,如果該組件包含有效的插件,將調用每一個(gè)插件的init
方法,把組件傳遞給插件,插件就能夠實(shí)現對組件的方法調用及事件應
用等,從而實(shí)現對組件功能的擴充。
renderTo
Mixed 混合數據參數,指定要渲染到節點(diǎn)的id,一個(gè)DOM的節點(diǎn)或一個(gè)已存
在的容器。如果使用了這個(gè)配置選項,則組件的render()就不是必需的了。
stateEvents
Array 定義需要保存組件狀態(tài)信息的事件。當指定的事件發(fā)生時(shí),組件會(huì )保存
它的狀態(tài)(默認為none),其值為這個(gè)組件支持的任意event類(lèi)型,包含
組件自身的或自定義事件。(例如:[‘click’,’customerchange’])。
stateId
String 組件的狀態(tài)ID,狀態(tài)管理器使用該id來(lái)管理組件的狀態(tài)信息,默認值為
組件的id。
style
String 給該組件的元素指定特定的樣式信息,有效的參數為
Ext.Element.applyStyles中的值。
xtype
String 指定所要創(chuàng )建組件的xtype,用于構造函數中沒(méi)有意義。該參數用于在
容器組件中創(chuàng )建創(chuàng )建子組件并延遲實(shí)例化和渲染時(shí)使用。如果是自定義
的組件,則需要用Ext.ComponentMgr.registerType來(lái)進(jìn)行注冊,才會(huì )支
持延遲實(shí)例化和渲染。
el
Mixed 相當于applyTo
<script>
function a() {
alert('some thing');
}
</script>
<input id="btnAlert" type="button" onclick="a();" value="alert框" />
點(diǎn)擊這個(gè)按鈕則會(huì )觸發(fā)onclick 事件,并執行onclick 事件處理函數中指定的代碼,這里
直接執行函數a 中的代碼,也即彈出一個(gè)簡(jiǎn)單的信息提示框。再簡(jiǎn)單修改一下上面的代碼,
內容如下:
上面的代碼在文檔加載的時(shí)候,就直接對btnAlert 的onclick 賦值,非常清晰的指明了
按鈕btnAlert 的onclick 事件響應函數為a,注意這里a 后面不能使用括號“()”。
ExtJS 中組件的事件處理跟上面相似,看下面的代碼:
Ext.get("btnAlert")得到一個(gè)與頁(yè)面中按鈕btnAlert 關(guān)聯(lián)的Ext.Element 對象,可以直接調
用該對象上的addListener 方法來(lái)給對象添加事件,同樣實(shí)現前面的效果。在調用addListener
方法的代碼中,第一個(gè)參數表示事件名稱(chēng),第二個(gè)參數表示事件處理器或整個(gè)響應函數。
ExtJS 支持事件隊列,可以往對象的某一個(gè)事件中添加多個(gè)事件響應函數,看下面的代碼:
addLinster 方法的另外一個(gè)簡(jiǎn)寫(xiě)形式是on,由于調用了兩次addListener 方法,因此當點(diǎn)
擊按鈕的時(shí)候會(huì )彈出兩次信息。
當然,ExtJS 還支持事件延遲處理或事件處理緩存等功能,比如下面的代碼:
<script>
function a()
{
alert('some thing');
}
window.onload=function(){
document.getElementById("btnAlert").onclick=a;
}
</script>
<input id="btnAlert" type="button" value="alert框" />
<script>
function a(){
alert('some thing');
}
Ext.onReady(function(){
Ext.get("btnAlert").addListener("click",a);
});
</script>
<input id="btnAlert" type="button" value="alert框" />
Ext.onReady(function(){
Ext.get("btnAlert").on("click",a);
Ext.get("btnAlert").on("click",a);
});
由于在調用addListener 的時(shí)候傳遞指定的delay 為2000,因此當用戶(hù)點(diǎn)擊按鈕的時(shí)候,
不會(huì )馬上執行事件響應函數,而是在2000 毫秒,也就是兩秒后才會(huì )彈出提示信息框。
當然,在使用Ext 的事件時(shí),我們一般是直接在控件上事件,每一個(gè)控件包含哪些事件,
在什么時(shí)候觸發(fā),觸發(fā)時(shí)傳遞的參數等,在ExtJS 項目的文檔中都有較為詳細的說(shuō)明。比
如對于所有的組件Component,都包含一個(gè)beforedestroy 事件,該事件會(huì )在Ext 銷(xiāo)毀這一個(gè)組件時(shí)觸發(fā),如果事件響應函數返回false,則會(huì )取消組件的銷(xiāo)毀操作。
由于在窗口對象的beforedestroy 事件響應函數返回值為false,因此執行這段程序,你
會(huì )發(fā)現這個(gè)窗口將無(wú)法關(guān)閉。組件的事件監聽(tīng)器可以直接在組件的配置屬性中直接聲明,如
下面的代碼與前面實(shí)現的功能一樣:
了解了ExtJS 中的基本事件處理及使用方法,就可以在你的應用中隨心所欲的進(jìn)行事件
相關(guān)處理操作了。
關(guān)于ExtJS 中事件處理中作用域、事件處理原理、給自定義的組件添加事件、處理相關(guān)的Ext.util.Observable
及Ext.EventManager 類(lèi)詳細介紹,請參考wlr.easyjf.com 中的VIP 文檔《ExtJS 中的事件處理詳解》。
Ext.onReady(function(){
Ext.get("btnAlert").on("click",a,this,{delay:2000});
});
Ext.onReady(function(){
var win=new Ext.Window({
title:"不能關(guān)閉的窗口", height:200, width:300
});
win.on("beforedestroy",function(obj){
alert("想關(guān)閉我,這是不可能的!");
obj.show();
return false;
});
win.show();});
Ext.onReady(function(){
var win=new Ext.Window({
title:"不能關(guān)閉的窗口",
height:200, width:300,
listeners:{"beforedestroy":function(obj){
alert("想關(guān)閉我,這是不可能的!");
obj.show(); return false;
}}
});
win.show();});
第四章、使用面板
4.1
Panel
面板Panel 是ExtJS 控件的基礎,很高級控件都是在面板的基礎上擴展的,還有其它大
多數控件也都直接或間接有關(guān)系。應用程序的界面一般情況下是由一個(gè)一個(gè)的面板通過(guò)不同
組織方式形成。
面板由以下幾個(gè)部分組成,一個(gè)頂部工具欄、一個(gè)底部工具欄、面板頭部、面板尾部、
面板主區域幾個(gè)部分組件。面板類(lèi)中還內置了面板展開(kāi)、關(guān)閉等功能,并提供一系列可重
用的工具按鈕使得我們可以輕松實(shí)現自定義的行為,面板可以放入其它任何容器中,面板本
身是一個(gè)容器,他里面又可以包含各種其它組件。
面板的類(lèi)名為Ext.Panel,其xtype 為panel,下面的代碼可以顯示出面板的各個(gè)組成部
分:
運行該代碼,可以得到如圖xx 所示的輸出結果,清楚的表示出了面板的各個(gè)組成部分。
一般情況下,頂部工具欄或底部工具欄只需要一個(gè),而面板中一般也很少直接包含按鈕,
一般會(huì )把面板上的按鈕直接放到工具欄上面。比如下面的代碼:
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"面板頭部header",
width:300,
height:200,
html:'<h1>面板主區域</h1>',
tbar:[{text:'頂部工具欄topToolbar'}],
bbar:[{text:'底部工具欄bottomToolbar'}],
buttons:[{text:"按鈕位于footer"}]
});
});
Ext.onReady(function(){
new Ext.Panel({
可以得到如圖xx所示的效果,該面板包含面板Header,一個(gè)頂部工具欄及面板區域三
個(gè)部分。
4.2
工具欄
面板中可以有工具欄,工具欄可以位于面板頂部或底部,Ext 中工具欄是由Ext.Toolbar
類(lèi)表示。工具欄上可以存放按鈕、文本、分隔符等內容。面板對象中內置了很多實(shí)用的工具
欄,可以直接通過(guò)面板的tools 配置選項往面板頭部加入預定義的工具欄選項。比如下面的
代碼:
renderTo:"hello",
title:"hello",
width:300,
height:200,
html:'<h1>Hello,easyjf open source!</h1>',
tbar:[{pressed:true,text:'刷新'}]
});
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"hello",
width:300,
height:200,
html:'<h1>Hello,easyjf open source!</h1>',
tools:[{
id:"save"},
{id:"help",
注意我們在Panel的構造函數中設置了tools屬性的值,表示在面板頭部顯示三個(gè)工具欄
選項按鈕,分別是保存"save"、"help"、"close"三種。代碼運行的效果圖如下:
點(diǎn)擊help按鈕會(huì )執行handler中的函數,顯示一個(gè)彈出對話(huà)框,而點(diǎn)擊其它的按鈕不
會(huì )有任何行為產(chǎn)生,因為沒(méi)有定義他們的heanlder。
除了在面板頭部加入這些已經(jīng)定義好的工具欄選擇按鈕以外,還可以在頂部或底工具欄
中加入各種工具欄選項。這些工具欄選項主要包括按鈕、文本、空白、填充條、分隔符等。
代碼:
handler:function(){Ext.Msg.alert('help','please help me!');}
},
{id:"close"}],
tbar:[{pressed:true,text:'刷新'}]
});
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"hello",
width:300,
height:200,
html:'<h1>Hello,easyjf open source!</h1>',
tbar:[new Ext.Toolbar.TextItem('工具欄:'),
{xtype:"tbfill"},
{pressed:true,text:'添加'},
{xtype:"tbseparator"},
{pressed:true,text:'保存'}
]
});
});
將會(huì )得到如圖xx所示的結果:
Ext中的工具欄項目主要包含下面的類(lèi):
Ext.Toolbar.Button-按鈕,xtype為tbbutton
TextItem-
Ext.Toolbar.Fill-
Separator-
Spacer-
SplitButton-
4.3
選項面板的TabPanel
在前面的示例中,為了顯示一個(gè)面板,我們需要在頁(yè)面上添加一個(gè),然后把Ext 控件
渲染到這個(gè)div 上。VeiwPort 代表整個(gè)瀏覽器顯示區域,該對象渲染到頁(yè)面的body 區域,
并會(huì )隨著(zhù)瀏覽器顯示區域的大小自動(dòng)改變,一個(gè)頁(yè)面中只能有一個(gè)ViewPort 實(shí)例??聪旅?span lang="EN-US">
的代碼:
運行上面的代碼會(huì )得到如圖xxx 所示的輸出結果。
Ext.onReady(function(){
new Ext.Viewport({
enableTabScroll:true,
layout:"fit",
items:[{title:"面板",
html:"",
bbar:[{text:"按鈕1"},
{text:"按鈕2"}]
}]
});
});
Viewport 不需要再指定renderTo,而我們也看到Viewport 確實(shí)填充了整個(gè)瀏覽器顯示區
域,并會(huì )隨著(zhù)瀏覽器顯示區域大小的改變而改改。
Viewport 主要用于應用程序的主界面,可以通過(guò)使用不同的布局來(lái)搭建出不同風(fēng)格的應
用程序主界面。在Viewport 上常用的布局有fit、border 等,當然在需要的時(shí)候其它布局也
會(huì )常用??聪旅娴拇a:
Ext.onReady(function(){
new Ext.Viewport({
enableTabScroll:true,
layout:"border",
items:[{title:"面板",
region:"north",
height:50,
html:"<h1>網(wǎng)站后臺管理系統!</h1>"
},
{title:"菜單",
region:"west",
width:200,
collapsible:true,
html:"菜單欄"
},
{
xtype:"tabpanel",
region:"center",
運行上面的程序會(huì )得如圖xx 所示的效果。
第五章、窗口及對話(huà)框
5.1
窗口基本應用
ExtJS 中窗口是由Ext.Window 類(lèi)定義,該類(lèi)繼承自Panel,因此窗口其實(shí)是一種特殊的
面板Panel。窗口包含了浮動(dòng)、可拖動(dòng)、可關(guān)閉、最大化、最小化等特性??聪旅娴拇a:
items:[{title:"面板1"},
{title:"面板2"}]
}
]
});
});
頁(yè)面中的html 內容:
執行上面的代碼,當點(diǎn)擊按鈕“新窗口”的時(shí)候,會(huì )在頁(yè)面中顯示一個(gè)窗口,窗口標題為
“窗口x”,窗口可以關(guān)閉,可以最大化,點(diǎn)擊最大化按鈕會(huì )最大化窗口,最大化的窗口可以
還原,如圖xxx 所示。
5.2
窗口分組
窗口是分組進(jìn)行管理的,可以對一組窗口進(jìn)行操作,默認情況下的窗口都在默認的組
Ext.WindowMgr 中。窗口分組由類(lèi)Ext.WindowGroup 定義,該類(lèi)包括bringToFront、getActive、
hideAll、sendToBack 等方法用來(lái)對分組中的窗口進(jìn)行操作。
var i=0;
function newWin()
{
var win=new Ext.Window({title:"窗口"+i++,
width:400,
height:300,
maximizable:true});
win.show();
}
Ext.onReady(function(){
Ext.get("btn").on("click",newWin);
});
<input id="btn" type="button" name="add" value="新窗口" />
看下面的代碼:
頁(yè)面中的html 代碼
執行上面的代碼,先點(diǎn)擊幾次“新窗口”按鈕,可以在頁(yè)面中顯示幾個(gè)容器,然后拖動(dòng)這
些窗口,讓他們在屏幕中不同的位置。然后點(diǎn)“放到后臺”按鈕,可以實(shí)現把最前面的窗口移
動(dòng)該組窗口的最后面去,點(diǎn)擊“隱藏所有”按鈕,可以隱藏當前打開(kāi)的所有窗口。如下圖所示:
var i=0,mygroup;
function newWin()
{
var win=new Ext.Window({title:"窗口"+i++,
width:400,
height:300,
maximizable:true,
manager:mygroup});
win.show();
}
function toBack()
{
mygroup.sendToBack(mygroup.getActive());
}f
unction hideAll()
{
mygroup.hideAll();
}
Ext.oReay(function(){
mygroup=new Ext.WindowGroup();
Ext.get("btn").on("click",newWin);
Ext.get("btnToBack").on("click",toBack);
Ext.get("btnHide").on("click",hideAll);
});
<input id="btn" type="button" name="add" value="新窗口" />
<input id="btnToBack" type="button" name="add" value="放到后臺" />
<input id="btnHide" type="button" name="add" value="隱藏所有" />
5.3
對話(huà)框
由于傳統使用alert、confirm 等方法產(chǎn)生的對話(huà)框非常古板,不好看。因此,ExtJS 提供
了一套非常漂亮的對話(huà)框,可以使用這些對話(huà)框代替傳統的alert、confirm 等,實(shí)現華麗的
應用程序界面。
Ext 的對話(huà)框都封裝在Ext.MessageBox 類(lèi),該類(lèi)還有一個(gè)簡(jiǎn)寫(xiě)形式即Ext.Msg,可以直
接通過(guò)Ext.MessageBox 或Ext.Msg 來(lái)直接調用相應的對話(huà)框方法來(lái)顯示Ext 對話(huà)框??聪?span lang="EN-US">
面的代碼:
Html 頁(yè)面中的內容:
執行程序,點(diǎn)擊上面的“alert 框”按鈕,將會(huì )在頁(yè)面上顯示如下圖所示的對話(huà)框。
Ext.onReady(function(){
Ext.get("btnAlert").on("click",function(){
Ext.MessageBox.alert("請注意","這是ExtJS的提示框");
});
});
<input id="btnAlert" type="button" value="alert框" />
除了alert 以外,Ext 還包含confirm、prompt、progress、wait 等對話(huà)框,另外我們可以
根據需要顯示自下定義的對話(huà)框。普通對話(huà)框一般包括四個(gè)參數,比如confirm 的方法簽
名為confirm ( String title, String msg, [Function fn], [Object scope] ) ,參數title 表示對話(huà)框的
標題,參數msg 表示對話(huà)框中的提示信息,這兩個(gè)參數是必須的;可選的參數fn 表示當關(guān)
閉對話(huà)框后執行的回調函數,參數scope 表示回調函數的執行作用域?;卣{函數可以包含兩
個(gè)參數,即button 與text,button 表示點(diǎn)擊的按鈕,text 表示對話(huà)框中有活動(dòng)輸入選項時(shí)輸
入的文本內容。我們可以在回調函數中通過(guò)button 參數來(lái)判斷用戶(hù)作了什么什么選擇,可
以通過(guò)text 來(lái)讀取在對話(huà)框中輸入的內容??聪旅娴睦樱?/span>]
Html 內容:
點(diǎn)擊對話(huà)框按鈕將會(huì )出現下面的對話(huà)框,然后選擇yes 或no 則會(huì )用傳統的提示框輸出
回調函數中button 及text 參數的內容。
因此,在實(shí)際的應用中,上面的代碼可以改成如下的內容:
這樣當用戶(hù)點(diǎn)擊對話(huà)框中的yes 按鈕時(shí),就會(huì )執行相應的操作,而選擇no 則忽略操作。
下面再看看prompt 框,我們看下面的代碼:
Ext.onReady(function(){
Ext.get("btn").on("click",function(){
Ext.MessageBox.confirm("請確認","是否真的要刪除指定的內容",function(button,text){
alert(button);
alert(text);
});
});
});
<input id="對話(huà)框" type="button" value="btn" />
Ext.onReady(function(){
Ext.get("btnAlert").on("click",function(){
Ext.MessageBox.confirm("請確認","是否真的要刪除指定的內容",function(button,text){
if(button=="yes"){
//執行刪除操作
alert("成功刪除");
}
});
});
});
Ext.onReady(function(){
Html 頁(yè)面:
點(diǎn)擊上面的“對話(huà)框”按鈕可以顯示如下圖所示的內容,如果點(diǎn)擊OK 按鈕則會(huì )輸入你輸
入的文本內容,選擇cancel 按鈕則會(huì )提示放棄了錄入,如下圖所示:
在實(shí)際應用中,可以直接使用MessageBox 的show 方法來(lái)顯示自定義的對話(huà)框,如下
面的代碼:
點(diǎn)擊“對話(huà)框”按鈕可顯示一個(gè)自定義的保存數據對話(huà)框,對話(huà)框中包含yes、no、cancel
三個(gè)按鈕,可以在回調函數save 中根據點(diǎn)擊的按鈕執行相應的操作,如圖xx 所示。
Ext.get("btn").on("click",function(){
Ext.MessageBox.prompt("輸入提示框","請輸入你的新年愿望:",function(button,text){
if(button=="ok"){
alert("你的新年愿望是:"+text);
}
else alert("你放棄了錄入!");
});
});
});
<input id="btn" type="button" value="對話(huà)框" />
function save(button)
{
if(button=="yes")
{
//執行數據保存操作
} else if(button=="no")
{
//不保存數據
} else
{
//取消當前操作
}
}
Ext.onReady(function(){
Ext.get("btn").on("click",function(){
Ext.Msg.show({
title:'保存數據',
msg: '你已經(jīng)作了一些數據操作,是否要保存當前內容的修改?',
buttons: Ext.Msg.YESNOCANCEL,
fn: save,
icon: Ext.MessageBox.QUESTION});
});
});
第六章、布局Layout
6.1
布局概述
所謂布局就是指容器組件中子元素的分布、排列組合方式。Ext 的所有容器組件都支持而局
操作,每一個(gè)容器都會(huì )有一個(gè)對應的布局,布局負責管理容器組件中子元素的排列、組合及
渲染方式等。
ExtJS 的布局基類(lèi)為Ext.layout.ContainerLayout,其它布局都是繼承該類(lèi)。ExtJS 的
容器組件包含一個(gè)layout 及layoutConfig 配置屬性,這兩個(gè)屬性用來(lái)指定容器使用的布局及布局的詳細配置信息,如果沒(méi)有指定容器組件的layout 則默認會(huì )使用ContainerLayout 作為布局,該布局只是簡(jiǎn)單的把元素放到容器中,有的布局需要layoutConfig 配置,有的則不需要layoutConfig 配置??创a:
上面的代碼我們創(chuàng )建了一個(gè)面板Panel,Panle 是一個(gè)容器組件,我們使用layout 指定該
面板使用Column 布局。該面板的子元素是兩個(gè)面板,這兩個(gè)面板都包含了一個(gè)與列布局相
關(guān)的配置參數屬性columnWidth,他們的值都是0.5,也就是每一個(gè)面板占一半的寬度。執
行上面的程序生成如下圖所示的結果:
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
width:400,
height:200,
layout:"column",
items:[{columnWidth:.5,
title:"面板1"},
{columnWidth:.5,
title:"面板2"}]
});
});
Ext中的一些容器組件都已經(jīng)指定所使用的布局,比如TabPanel使用card布局、
FormPanel使用form布局,GridPanel中的表格使用column布局等,我們在使用這些組件的
時(shí)候,不能給這些容器組件再指定另外的布局。
ExtJS2.0 一共包含十種布局,常用的布局有border、column、fit、form、card、tabel
等布局,下面我們分別對這幾種布局作簡(jiǎn)單的介紹。
6.2
Border
區域布局
Border 布局由類(lèi)Ext.layout.BorderLayout定義,布局名稱(chēng)為border。該布局把容器分成東南西北中五個(gè)區域,
分別由east,south, west,north, cente來(lái)表示,在往容器中添加子元素的時(shí)候,我們只需要指定這些子元素
所在的位置,Border布局會(huì )自動(dòng)把子元素放到布局指定的位置??聪旅娴拇a:
Ext.onReady(function(){
new Ext.Viewport({
layout:"border",
items:[{region:"north",
height:50,
title:"頂部面板"},
{region:"south",
height:50,
title:"底部面板"},
{region:"center",
title:"中央面板"},
{region:"west",
width:100,
title:"左邊面板"},
{region:"east",
width:100,
title:"右邊面板"}
]
});
});
執行上面的代碼將會(huì )在頁(yè)面中輸出包含上下左右中五個(gè)區域的面板,如下圖所示:
6.2
Column
列布局
Column 列布局由Ext.layout.ColumnLayout 類(lèi)定義,名稱(chēng)為column。列布局把整個(gè)容器
組件看成一列,然后往里面放入子元素的時(shí)候,可以通過(guò)在子元素中指定使用columnWidth
或width 來(lái)指定子元素所占的列寬度。columnWidth 表示使用百分比的形式指定列寬度,而
width 則是使用絕對象素的方式指定列寬度,在實(shí)際應用中可以混合使用兩種方式??聪旅?span lang="EN-US">
的代碼:
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
layout:"column",
width:500,
height:100,
items:[{title:"列1",width:100},
{title:"列2",width:200},
{title:"列3",width:100},
{title:"列4"}
]
}
);
});
上面的代碼在容器組件中放入了四個(gè)元素,在容器組件中形成4 列,列的寬度分別為
100,200,100 及剩余寬度,執行結果如下圖所示。
也可使用columnWidth 來(lái)定義子元素所占的列寬度,看下面的代碼:
注意columnWidth 的總和應該為1,執行代碼將生成如下圖所示的內容:
在實(shí)際應用中還可以混合使用,看下面的代碼:
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
layout:"column",
width:500,
height:100,
items:[{title:"列1",columnWidth:.2},
{title:"列2",columnWidth:.3},
{title:"列3",columnWidth:.3},
{title:"列4",columnWidth:.2}
]
}
);
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
layout:"column",
width:500,
height:100,
items:[{title:"列1",width:200},
執行上面的代碼將會(huì )生成如下圖所示的結果:
6.3
Fit
布局
Column 列布局由Ext.layout.ColumnLayout 類(lèi)定義,名稱(chēng)為column。列布局把整個(gè)容器
組件看成一列,然后往里面放入子元素的時(shí)候,可以通過(guò)在子元素中指定使用columnWidth
或width 來(lái)指定子元素所占的列寬度。columnWidth 表示使用百分比的形式指定列寬度,而
width 則是使用絕對象素的方式指定列寬度,在實(shí)際應用中可以混合使用兩種方式??聪旅?span lang="EN-US">
的代碼:
上面的代碼在容器組件中放入了四個(gè)元素,在容器組件中形成4 列,列的寬度分別為
100,200,100 及剩余寬度,執行結果如下圖所示。
{title:"列2",columnWidth:.3},
{title:"列3",columnWidth:.3},
title:"列4",columnWidth:.4}
] }
);
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
layout:"column",
width:500,
height:100,
items:[{title:"列1",width:100},
{title:"列2",width:200},
{title:"列3",width:100},
{title:"列4"}
]
}
);
});
再看使用Fit 布局后的代碼,如下:
上面的代碼指定父容器使用Fit 布局,因此子將自動(dòng)填滿(mǎn)整個(gè)父容器。輸出的圖形如下:
如果容器組件中有多個(gè)子元素,則只會(huì )顯示一個(gè)元素,如下面的代碼:
輸出的結果如下:
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
layout:"fit",
width:500,
height:100,
items:[{title:"子元素",html:"這是子元素中的內容"}
] }
);
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
layout:"fit",
width:500,
height:100,
items:[{title:"子元素1",html:"這是子元素1中的內容"},
{title:"子元素2",html:"這是子元素2中的內容"}
] }
);
});
如果不使用布局Fit,代碼如下:
輸出的結果如下圖所示:
6.4
Form
布局
Form 布局由類(lèi)Ext.layout.FormLayout 定義,名稱(chēng)為form,是一種專(zhuān)門(mén)用于管理表單中
輸入字段的布局,這種布局主要用于在程序中創(chuàng )建表單字段或表單元素等使用??聪旅娴拇?span lang="EN-US">
碼:
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
width:500,
height:120,
items:[{title:"子元素1",html:"這是子元素1中的內容"},
{title:"子元素2",html:"這是子元素2中的內容"}
] }
);
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
width:300,
layout:"form",
hideLabels:false,
labelAlign:"right",
上面的代碼創(chuàng )建了一個(gè)面板,面板使用Form 布局,面板中包含三個(gè)子元素,這些子元
素都是文本框字段,在父容器中還通過(guò)hideLabels、labelAlign 等配置屬性來(lái)定義了是否隱
藏標簽、標簽對齊方式等。上面代碼的輸出結果如下圖所示:
可以在容器組件中把hideLabels 設置為true,這樣將不會(huì )顯示容器中字段的標簽了,如
下圖所示:
在實(shí)際應用中,Ext.form.FormPanel 這個(gè)類(lèi)默認布局使用的是Form 布局,而且FormPanel
還會(huì )創(chuàng )建與<form> 標簽相關(guān)的組件,因此一般情況下我們直接使用FormPanel 即可。上面
的例子可改寫(xiě)成如下的形式:
height:120,
defaultType: 'textfield',
items:[
{fieldLabel:"請輸入姓名",name:"name"},
{fieldLabel:"請輸入地址",name:"address"},
{fieldLabel:"請輸入電話(huà)",name:"tel"}
] }
);
});
Ext.onReady(function(){
new Ext.form.FormPanel({
renderTo:"hello",
title:"容器組件",
width:300,
labelAlign:"right",
height:120,
defaultType: 'textfield',
items:[
{fieldLabel:"請輸入姓名",name:"name"},
{fieldLabel:"請輸入地址",name:"address"},
{fieldLabel:"請輸入電話(huà)",name:"tel"}
程序結果與前面使用Ext.Panel 并指定form 布局的一樣,如下圖所示:
6.5
Accordion
布局
Accordion 布局由類(lèi)Ext.layout.Accordion 定義,名稱(chēng)為accordion,表示可折疊的布局,也就
是說(shuō)使用該布局的容器組件中的子元素是可折疊的形式。來(lái)看下面的代碼:
上面的代碼定義了一個(gè)容器組件,指定使用Accordion 布局,該容器組件中包含三個(gè)子
元素,在layoutConfig 中指定布局配置參數animate 為true,表示在執行展開(kāi)折疊時(shí)是否應
用動(dòng)畫(huà)效果。執行結果將生成如下圖所示的界面:
] }
);
});
Ext.onReady(function(){
new Ext.Panel({
renderTo:"hello",
title:"容器組件",
width:500,
height:200,
layout:"accordion",
layoutConfig: {
animate: true
},
items:[{title:"子元素1",html:"這是子元素1中的內容"},
{title:"子元素2",html:"這是子元素2中的內容"},
{title:"子元素3",html:"這是子元素3中的內容"}
] }
);
});
點(diǎn)擊每一個(gè)子元素的頭部名稱(chēng)或右邊的按鈕,則會(huì )展開(kāi)該面板,并收縮其它已經(jīng)展
開(kāi)的面板,如下圖:
6.6
Table
布局及其它布局
Table 布局由類(lèi)Ext.layout.TableLayout 定義,名稱(chēng)為table,該布局負責把容器中的子元
素按照類(lèi)似普通html 標簽
Ext.onReady(function(){
var panel=new Ext.Panel({
renderTo:"hello",
title:"容器組件",
width:500,
height:200,
layout:"table",
layoutConfig: {
columns: 3
},
items:[{title:"子元素1",html:"這是子元素1中的內容",rowspan:2,height:100},
{title:"子元素2",html:"這是子元素2中的內容",colspan:2},
{title:"子元素3",html:"這是子元素3中的內容"},
{title:"子元素4",html:"這是子元素4中的內容"}
上面的代碼創(chuàng )建了一個(gè)父容器組件,指定使用Table 布局,layoutConfig 使用columns
指定父容器分成3 列,子元素中使用rowspan 或colspan 來(lái)指定子元素所橫跨的單元格數。
程序的運行效果如下圖所示:
除了前面介紹的幾種布局以外, Ext2.0 中還包含其它的Ext.layout.AbsoluteLayout、
Ext.layout.AnchorLayout 等布局類(lèi),這些布局主要作為其它布局的基類(lèi)使用,一般情況下我
們不會(huì )在應用中直接使用。另外,我們也可以繼承10 種布局類(lèi)的一種,來(lái)實(shí)現自定義的布
局。
關(guān)于ExtJS布局的詳細說(shuō)明,請參考wlr.easyjf.com中的VIP文檔《ExtJS布局Layout詳解(1)、(2)、(3)》。
第七章、使用表格控件
7.1
基本表格GridPanel
ExtJS 中的表格功能非常強大,包括了排序、緩存、拖動(dòng)、隱藏某一列、自動(dòng)顯示行號、
列匯總、單元格編輯等實(shí)用功能。
表格由類(lèi)Ext.grid.GridPanel 定義,繼承自Panel,其xtype 為grid。ExtJS 中,表格Grid
必須包含列定義信息, 并指定表格的數據存儲器Store 。表格的列信息由類(lèi)
Ext.grid.ColumnModel 定義、而表格的數據存儲器由Ext.data.Store 定義,數據存儲器根據解析的數據不同分為JsonStore、SimpleStroe、GroupingStore 等。
我們首先來(lái)看最簡(jiǎn)單的使用表格的代碼:
] }
);
});
Ext.onReady(function(){
var data=[ [1, 'EasyJWeb', 'EasyJF','www.easyjf.com'],
[2, 'jfox', 'huihoo','www.huihoo.org'],
執行上面的代碼,可以得到一個(gè)簡(jiǎn)單的表格,如下圖所示:
上面的代碼中,第一行“var data=…”用來(lái)定義表格中要顯示的數據,這是一個(gè)[][]二維數組;第二行“var store=…”用來(lái)創(chuàng )建一個(gè)數據存儲,這是GridPanel 需要使用配置屬性,數據存儲器Store 負責把各種各樣的數據(如二維數組、JSon 對象數組、xml 文本)等轉換成ExtJS的數據記錄集Record,關(guān)于數據存儲器Store 我們將在下一章中作專(zhuān)門(mén)介紹。第三行“var grid= new Ext.grid.GridPanel(…)”負責創(chuàng )建一個(gè)表格,表格包含的列由columns 配置屬性來(lái)描述,columns 是一數組,每一行數據元素描述表格的一列信息,表格的列信息包含列頭顯示文本(header)、列對應的記錄集字段(dataIndex)、列是否可排序(sorable)、列的渲染函數(renderer)、寬度(width)、格式化信息(format)等,在上面的列子中只用到了header 及dataIndex。
下面我們看簡(jiǎn)單看看表格的排序及隱藏列特性,簡(jiǎn)單修改一下上面的代碼,內容如下:
[3, 'jdon', 'jdon','www.jdon.com'],
[4, 'springside', 'springside','www.springside.org.cn'] ];
var store=new Ext.data.SimpleStore({data:data,fields:["id","name","organization","homepage"]});
var grid = new Ext.grid.GridPanel({
renderTo:"hello",
title:"中國Java開(kāi)源產(chǎn)品及團隊",
height:150,
width:600,
columns:[{header:"項目名稱(chēng)",dataIndex:"name"},
{header:"開(kāi)發(fā)團隊",dataIndex:"organization"},
{header:"網(wǎng)址",dataIndex:"homepage"}],
store:store,
autoExpandColumn:2
});
});
Ext.onReady(function(){
var data=[ [1, 'EasyJWeb', 'EasyJF','www.easyjf.com'],
[2, 'jfox', 'huihoo','www.huihoo.org'],
[3, 'jdon', 'jdon','www.jdon.com'],
[4, 'springside', 'springside','www.springside.org.cn'] ];
var store=new Ext.data.SimpleStore({data:data,fields:["id","name","organization","homepage"]});
var colM=new Ext.grid.ColumnModel([{header:"項目名稱(chēng)",dataIndex:"name",sortable:true},
{header:"開(kāi)發(fā)團隊",dataIndex:"organization",sortable:true},
直接使用new Ext.grid.ColumnModel 來(lái)創(chuàng )建表格的列信定義信息,在“項目名稱(chēng)“及“開(kāi)
發(fā)團隊”列中我們添加了sortable 為true 的屬性,表示該列可以排序,執行上面的代碼,我們可以得到一個(gè)支持按“項目名稱(chēng)“或“開(kāi)發(fā)團隊”的表格,如圖xxx 所示。
(按項目名稱(chēng)排序)
(可排序的列表頭后面小按鈕可以彈出操作菜單)
{header:"網(wǎng)址",dataIndex:"homepage"}]);
var grid = new Ext.grid.GridPanel({
renderTo:"hello",
title:"中國Java開(kāi)源產(chǎn)品及團隊",
height:200,
width:600,
cm:colM,
store:store,
autoExpandColumn:2
});
});
另外,每一列的數據渲染方式還可以自己定義,比如上面的表格中,我們希望用戶(hù)在表
格中點(diǎn)擊網(wǎng)址則直接打開(kāi)這些開(kāi)源團隊的網(wǎng)站,也就是需要給網(wǎng)址這一列添加上超級連接。
下面的代碼實(shí)現這個(gè)功能:
上面的代碼跟前面的示例差別不大,只是在定義“網(wǎng)址”列的時(shí)候多了一個(gè)renderer 屬性,
即{header:"網(wǎng)址",dataIndex:"homepage",renderer:showUrl}。showUrl 是一個(gè)自定義的函數,內容就是根據傳入的value 參數返回一個(gè)包含<a>標簽的html 片段。運行上面的代碼顯示結果如下圖所示:
function showUrl(value)
{
return ""+value+"";
}
Ext.onReady(function(){
var data=[ [1, 'EasyJWeb', 'EasyJF','www.easyjf.com'],
[2, 'jfox', 'huihoo','www.huihoo.org'],
[3, 'jdon', 'jdon','www.jdon.com'],
[4, 'springside', 'springside','www.springside.org.cn'] ];
var store=new Ext.data.SimpleStore({data:data,fields:["id","name","organization","homepage"]});
var colM=new Ext.grid.ColumnModel([{header:"項目名稱(chēng)",dataIndex:"name",sortable:true},
{header:"開(kāi)發(fā)團隊",dataIndex:"organization",sortable:true},
{header:"網(wǎng)址",dataIndex:"homepage",renderer:showUrl}]);
var grid = new Ext.grid.GridPanel({
renderTo:"hello",
title:"中國Java開(kāi)源產(chǎn)品及團隊",
height:200,
width:600,
cm:colM,
store:store,
autoExpandColumn:2
});
});
自定義的列渲染函數可以實(shí)現在單元格中顯示自己所需要的各種信息,只是的瀏覽器能
處理的html 都可以。
除了二級數組以外,表格還能顯示其它格式的數據嗎?答案是肯定的,下面假如我們的
表格數據data 定義成了下面的形式:
也就是說(shuō)數據變成了一維數組,數組中的每一個(gè)元素是一個(gè)對象,這些對象包含name、
organization、homepage、id 等屬性。要讓表格顯示上面的數據,其實(shí)非常簡(jiǎn)單,只需要把store 改成用Ext.data.JsonStore 即可,代碼如下:
var data=[{id:1,
name:'EasyJWeb',
organization:'EasyJF',
homepage:'www.easyjf.com'},
{id:2,
name:'jfox',
organization:'huihoo',
homepage:'www.huihoo.org'},
{id:3,
name:'jdon',
organization:'jdon',
homepage:'www.jdon.com'},
{id:4,
name:'springside',
organization: 'springside',
homepage:'www.springside.org.cn'}
];
var store=new Ext.data.JsonStore({data:data,fields:["id","name","organization","homepage"]});
var colM=new Ext.grid.ColumnModel([{header:"項目名稱(chēng)",dataIndex:"name",sortable:true},
{header:"開(kāi)發(fā)團隊",dataIndex:"organization",sortable:true},
{header:"網(wǎng)址",dataIndex:"homepage",renderer:showUrl}]);
var grid = new Ext.grid.GridPanel({
renderTo:"hello",
title:"中國Java開(kāi)源產(chǎn)品及團隊",
上面的代碼得到的結果與前面的一樣。當然,表格同樣能顯示xml 格式的數據,假如
上面的數據存放成hello.xml 文件中,內容如下:
為了把這個(gè)xml 數據用ExtJS 的表格Grid 進(jìn)行顯示,我們只需要把store 部分的內
容調整成如下的內容即可:
height:200,
width:600,
cm:colM,
store:store,
autoExpandColumn:2
});
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<row>
<id>1</id>
<name>EasyJWeb</name>
<organization>EasyJF</organization>
<homepage>www.easyjf.com</homepage>
</row>
<row>
<id>2</id>
<name>jfox</name>
<organization>huihoo</organization>
<homepage>www.huihoo.org</homepage>
</row>
<row>
<id>3</id>
<name>jdon</name>
<organization>jdon</organization>
<homepage>www.jdon.com</homepage>
</row>
<row>
<id>4</id>
<name>springside</name>
<organization>springside</organization>
<homepage>www.springside.org.cn</homepage>
</row>
</dataset>
其它的部分不用改變,完整的代碼如下:
store.laod()是用來(lái)加載數據,執行上面的代碼產(chǎn)生的表格與前面的完全一樣。
7.2
可編輯表格EditorGridPanel
可編輯表格是指可以直接在表格的單元格對表格的數據進(jìn)行編輯,ExtJS 中的可編輯表格由
類(lèi)Ext.grid.EditorGridPanel 表示,xtype 為editorgrid。使用EditorGridPanel 與使用普通的
var store=new Ext.data.Store({
url:"hello.xml",
reader:new Ext.data.XmlReader({
record:"row"},
["id","name","organization","homepage"])
});
function showUrl(value)
{
return "<a href='http://"+value+"' target='_blank'>"+value+"</a>";
}
Ext.onReady(function(){
var store=new Ext.data.Store({
url:"hello.xml",
reader:new Ext.data.XmlReader({
record:"row"},
["id","name","organization","homepage"])
});
var colM=new Ext.grid.ColumnModel([{header:"項目名稱(chēng)",dataIndex:"name",sortable:true},
{header:"開(kāi)發(fā)團隊",dataIndex:"organization",sortable:true},
{header:"網(wǎng)址",dataIndex:"homepage",renderer:showUrl}]);
var grid = new Ext.grid.GridPanel({
renderTo:"hello",
title:"中國Java開(kāi)源產(chǎn)品及團隊",
height:200,
width:600,
cm:colM,
store:store,
autoExpandColumn:2
});
store.load();
});
GridPanel 方式一樣,區別只是在定義列信息的時(shí)候,可以指定某一列使用的編輯即可,下
面來(lái)看一個(gè)簡(jiǎn)單的示例。
Ext.onReady(function(){
var data=[{id:1,
name:'小王',
email:'xiaowang@easyjf.com',
sex:'男',
bornDate:'
{id:1,
name:'小李',
email:'xiaoli@easyjf.com',
sex:'男',
bornDate:'
{id:1,
name:'小蘭',
email:'xiaoxiao@easyjf.com',
sex:'女',
bornDate:'
];
var store=new Ext.data.JsonStore({
data:data,
fields:["id","name","sex","email",{name:"bornDate",type:"date",dateFormat:"Y-n-j"}]
});
var colM=new Ext.grid.ColumnModel([{
header:"姓名",
dataIndex:"name",
sortable:true,
editor:new Ext.form.TextField()},
{header:"性別",
dataIndex:"sex"
},
{header:"出生日期",
dataIndex:"bornDate",
width:120,
renderer:Ext.util.Format.dateRenderer('Y年m月d日')},
{header:"電子郵件",
dataIndex:"email",
sortable:true,
editor:new Ext.form.TextField()}
]);
var grid = new Ext.grid.EditorGridPanel({
renderTo:"hello",
上面的程序首先定義了一個(gè)包含學(xué)生信息的對象數組,然后創(chuàng )建了一個(gè)JsonStore,在創(chuàng )建這個(gè)store 的時(shí)候,指定bornDate 列的類(lèi)型為日期date 類(lèi)型,并使用dateFormat 來(lái)指定日期信息的格式為"Y-n-j",Y 代表年,n 代表月,j 代表日期。定義表格列模型的時(shí)候,對于“姓名” 及“ 電子郵件” 列我們使用editor 來(lái)定義該列使用的編輯器,這里是使用Ext.form.TextField,最后使用new Ext.grid.EditorGridPanel(…)來(lái)創(chuàng )建一個(gè)可編輯的表格。執行上面的程序可以生成一個(gè)表格,雙擊表格中的“姓名”、或“電子郵件”單元格中的信息可以觸發(fā)單元格的編輯,可以在單元格的文本框中直接編輯表格中的內容,修改過(guò)的單元格會(huì )有特殊的標記,如下圖所示:為了能編輯“性別”及“出生日期”列,同樣只需要在定義該列的時(shí)候指定editor 即可。由于出生日期是日期類(lèi)型,因此我們可以使用日期編輯器來(lái)編輯,“性別”一列的數據不應該讓用戶(hù)直接輸入,而應該是通過(guò)下拉框進(jìn)行選擇。日期編輯器可以直接使用Ext.form.DateField組件,下拉選擇框編輯器可以使用Ext.form.ComboBox 組件,下面是實(shí)現對性別及出生日期等列信息編輯的代碼:
title:"學(xué)生基本信息管理",
height:200,
width:600,
cm:colM,
store:store,
autoExpandColumn:3
});
});
var colM=new Ext.grid.ColumnModel([{
header:"姓名",
dataIndex:"name",
sortable:true,
editor:new Ext.form.TextField()},
{header:"性別",
dataIndex:"sex",
editor:new Ext.form.ComboBox({transform:"sexList",
triggerAction: 'all',
lazyRender:true})
注意在定義EditorGridPanel 的時(shí)候,我們增加了一個(gè)屬性“clicksToEdit:1”,表示點(diǎn)擊一次單元格即觸發(fā)編輯,因為默認情況下該值為2,需要雙擊單元格才能編輯。為了給
ComboBox 中填充數據,我們使用設置了該組件的transform 配置屬性值為sexList,sexList
是一個(gè)傳統的<select>框,我們需要在html 頁(yè)面中直接定義,代碼如下:
執行上面的程序,我們可以得到一個(gè)能對表格中所有數據進(jìn)行編輯的表格了。點(diǎn)擊上面
的“性別”一列的單元格時(shí),會(huì )出現一個(gè)下拉選擇框,點(diǎn)擊“出生日期”一列的單元格時(shí),會(huì )出現一個(gè)日期數據選擇框,如圖xxxx 所示:
},
{header:"出生日期",
dataIndex:"bornDate",
width:120,
renderer:Ext.util.Format.dateRenderer('Y年m月d日'),
editor:new Ext.form.DateField({format:'Y年m月d日'})},
{header:"電子郵件",
dataIndex:"email",
sortable:true,
editor:new Ext.form.TextField()}
]);
var grid = new Ext.grid.EditorGridPanel({
renderTo:"hello",
title:"學(xué)生基本信息管理",
height:200,
width:600,
cm:colM,
store:store,
autoExpandColumn:3,
clicksToEdit:1
});
<select>
<option>男</option>
<option>女</option>
</select>
(編輯性別列中的數據)
(編輯出生日期列中的數據)
那么如何保存編輯后的數據呢?答案是直接使用afteredit 事件。當對一個(gè)單元格進(jìn)行編
輯完之后,就會(huì )觸發(fā)afteredit 事件,可以通過(guò)該事件處理函數來(lái)處理單元格的信息編輯。比如在http://wlr.easyjf.com 這個(gè)單用戶(hù)blog 示例中,當我們編輯一個(gè)日志目錄的時(shí)候,需要把編輯后的數據保存到服務(wù)器,代碼如下:
this.grid.on("afteredit",this.afterEdit,this);
…
afterEdit:function(obj){
var r=obj.record;
var id=r.get("id");
var name=r.get("name");
var c=this.record2obj(r);
var tree=this.tree;
var node=tree.getSelectionModel().getSelectedNode();
if(node && node.id!="root")c.parentId=node.id;
if(id=="-1" && name!=""){
topicCategoryService.addTopicCategory(c,function(id){
if(id)r.set("id",id);
if(!node)node=tree.root;
node.appendChild(new Ext.tree.TreeNode({
id:id,
text:c.name,
leaf:true
}));
node.getUI().removeClass('x-tree-node-leaf');
node.getUI().addClass('x-tree-node-expanded');
node.expand();
});
關(guān)于可編輯表格控件的詳細說(shuō)明,請參考wlr.easyjf.com 中的VIP 文檔《ExtJS 可編輯表格
EditorGridPanel 詳解》。
7.3
與服務(wù)器交互
在實(shí)際的應用中,表格中的數據一般都是直接存放在數據庫表或服務(wù)器的文件中。因此,
在使用表格控件的時(shí)候經(jīng)常需要與服務(wù)器進(jìn)行交互。ExtJS 使用Ajax 方式提供了一套與服務(wù)器交互的機制,也就是可以不用刷新頁(yè)面,就可以訪(fǎng)問(wèn)服務(wù)器的程序進(jìn)行數據讀取或數據保存等操作。
比如前面在表格中顯示xml 文檔中數據的例子中,就是一個(gè)非常簡(jiǎn)單的從服務(wù)器端讀
取數據的例子,再回顧一下代碼:
因為Sote 組件接受一個(gè)參數url,如果設置url,則ExtJS 會(huì )創(chuàng )建一個(gè)與服務(wù)器交互的
Ext.data.HttpProxy 對象,該對象通過(guò)指定的Connection 或Ext.Ajax.request 來(lái)向服務(wù)端發(fā)送請求,從而可以讀取到服務(wù)器端的數據。
經(jīng)驗表明,服務(wù)器端產(chǎn)生JSon 數據是一種非常不錯的選擇,也就是說(shuō)假如服務(wù)器的
url“student.ejf?cmd=list”產(chǎn)生下面的JSON 數據輸出:
}
else if(name!="")
{
topicCategoryService.updateTopicCategory(r.get("id"),c,function(ret){
if(ret)tree.getNodeById(r.get("id")).setText(c.name);
});
}
}
var store=new Ext.data.Store({
url:"hello.xml",
reader:new Ext.data.XmlReader({
record:"row"},
["id","name","organization","homepage"])
});
{results:[{id:1,
name:'小王',
email:'xiaowang@easyjf.com',
sex:'男',
bornDate:'
{id:1,
name:'小李',
email:'xiaoli@easyjf.com',
則前面顯示學(xué)習信息編輯表格的store 可以創(chuàng )建成下面的形式:
或者:
其中root 表示包含記錄集數據的屬性。
如果在運行程序中需要給服務(wù)器端發(fā)送數據的時(shí)候,此時(shí)可以直接使用ExtJS 中提供的
Ext.Ajax 對象的request 方法。比如下面的代碼實(shí)現放服務(wù)器的student.ejf?cmd=save 這個(gè)url發(fā)起一個(gè)請求,并在params 中指定發(fā)送的Student 對象:
sex:'男',
bornDate:'
{id:1,
name:'小蘭',
email:'xiaoxiao@easyjf.com',
sex:'女',
bornDate:'
] }
var store=new Ext.data.Store({
url:"student.ejf?cmd=list",
reader:new Ext.data.JsonReader({
root:"result"},
["id","name","organization","homepage"])
});
var store=new Ext.data.JsonStore({
url:"student.ejf?cmd=list",
root:"result",
fields:["id","name","organization","homepage"]});
var store=new Ext.data.JsonStore({
url:"student.ejf?cmd=list",
root:"result",
fields:["id","name","organization","homepage"]});
function sFn()
{
alert('保存成功');
}
function fFn()
{
alert('保存失敗');
}
Ext.Ajax.request({
url: 'student.ejf?cmd=save’
success: sFn
第八章、數據存儲Stroe
8.1
Record
在前面的表格應用中,我們已經(jīng)知道表格的數據是存放類(lèi)型為Store 的數據存儲器中,
通過(guò)指定表格Grid 的store 屬性來(lái)設置表格中顯示的數據,通過(guò)調用store 的load 或reload方法可以重新加載表格中的數據。ExtJS 中用來(lái)定義控件中使用數據的API 位于Ext.dd 命名空間中,本章我們重點(diǎn)對ExtJS 中的數據存儲Store 進(jìn)行介紹。
1、Record
首先需要明確是,ExtJS 中有一個(gè)名為Record 的類(lèi),表格等控件中使用的數據是存放在
Record 對象中,一個(gè)Record 可以理解為關(guān)系數據表中的一行,也可以稱(chēng)為記錄。Record 對
象中即包含了記錄(行中各列)的定義信息(也就是該記錄包含哪些字段,每一個(gè)字段的數
據類(lèi)型等),同時(shí)又包含了記錄具體的數據信息(也就是各個(gè)字段的值)。
我們來(lái)看直接使用Record 的代碼:
failure: fFn,
params: { name: '小李',email: ' xiaoli@easyjf.com',bornDate: '
});
Ext.onReady(function(){
var MyRecord = Ext.data.Record.create([
{name: 'title'},
{name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'},
{name: 'lastLoginTime', mapping: 'loginTime', type: 'date'}
]);
var r=new MyRecord({
title:"日志標題",
username:"easyjf",
loginTimes:100,
loginTime:new Date()
});
alert(MyRecord.getField("username").mapping);
alert(MyRecord.getField("lastLoginTime").type);
alert(r.data.username);
首先使用Record 的create 方法創(chuàng )建一個(gè)記錄集MyRecord,MyRecord 其實(shí)是一個(gè)類(lèi),
該類(lèi)包含了記錄集的定義信息,可以通過(guò)MyRecord 來(lái)創(chuàng )建包含字段值的Record 對象。在
上面的代碼中,最后的幾條語(yǔ)句用來(lái)輸出記錄集的相關(guān)信息,MyRecord.getField("username")可以得到記錄中username 列的字段信息,r.get("loginTimes")可以得到記錄loginTimes 字段的值,而r.data.username 同樣能得到記錄集中username 字段的值。對Record 有了一定的了解,那么要操作記錄集中的數據就非常簡(jiǎn)單了,比如r.set(name,value)可以設置記錄中某指定字段的值,r. dirty 可以得到當前記錄是否有字段的值被更改過(guò)等等。
8.2
Store
Store 可以理解為數據存儲器,可以理解為客戶(hù)端的小型數據表,提供緩存等功能。在
ExtJS 中,GridPanel、ComboBox、DataView 等控件一般直接與Store 打交道,直接通過(guò)store
來(lái)獲得控件中需要展現的數據等。一個(gè)Store 包含多個(gè)Record,同時(shí)Store 又包含了數據來(lái)
源,數據解析器等相關(guān)信息,Store 通過(guò)調用具體的數據解析器(DataReader)來(lái)解析指定類(lèi)型或格式的數據(DataProxy),并轉換成記錄集的形式保存在Store 中,作為其它控件的數據輸入。數據存儲器由Ext.data.Store 類(lèi)定義,一個(gè)完整的數據存儲器要知道數據源(DataProxy)及數據解析方式(DataReader)才能工作,在Ext.data.Store 類(lèi)中數據源由proxy 配置屬性定義、數據解析(讀?。┢饔?/span>reader 配置屬性定義,一個(gè)較為按部就班創(chuàng )建Store 的代碼如下:
alert(r.get("loginTimes"));
});
var MyRecord = Ext.data.Record.create([
{name: 'title'},
{name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'},
{name: 'lastLoginTime', mapping: 'loginTime', type: 'date'}
]);
var dataProxy=new Ext.data.HttpProxy({url:"link.ejf"});
var theReader=new Ext.data.JsonReader({
totalProperty: "results",
root: "rows",
id: "id"
},MyRecord);
var store=new Ext.data.Store({
proxy:dataProxy,
reader:theReader
});
當然,這樣的難免代碼較多,Store 中本身提供了一些快捷創(chuàng )建Store 的方式,比如上面
的示例代碼中可以不用先創(chuàng )建一個(gè)HttpProxy,只需要在創(chuàng )建Store 的時(shí)候指定一個(gè)url 配置參數,就會(huì )自動(dòng)使用HttpProxy 來(lái)加載參數。比如,上面的代碼可以簡(jiǎn)化成:
雖然不再需要手動(dòng)創(chuàng )建HttpProxy 了,但是仍然需要創(chuàng )建DataReader 等,畢竟還是復雜,
ExtJS 進(jìn)一步把這種常用的數據存儲器進(jìn)行了封裝,在Store 類(lèi)的基礎上提供了SimpleStore、SimpleStore、GroupingStore 等,直接使用SimpleStore,則上面的代碼可以進(jìn)一步簡(jiǎn)化成下面的內容:
store.load();
var MyRecord = Ext.data.Record.create([
{name: 'title'},
{name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'},
{name: 'lastLoginTime', mapping: 'loginTime', type: 'date'}
]);
var theReader=new Ext.data.JsonReader({
totalProperty: "results",
root: "rows",
id: "id"
},MyRecord);
var store=new Ext.data.Store({
url:"link.ejf",
proxy:dataProxy,
reader:theReader
});
store.load();
var store=new Ext.data.JSonStore({
url:"link.ejf?cmd=list",
totalProperty: "results",
root: "rows",
fields:['title', {name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'},
{name: 'lastLoginTime', mapping: 'loginTime', type: 'date'}
]
});
store.load();
8.3
DataReader
DataReader 表示數據讀取器,也就是數據解析器,其負責把從服務(wù)器或者內存數組、xml
文檔中獲得的雜亂信息轉換成ExtJS 中的記錄集Record 數據對象,并存儲到Store 里面的記錄集數組中。
數據解析器的基類(lèi)由Ext.data.DataReader定義,其它具體的數據解析器都是該類(lèi)的子類(lèi),
ExtJS 中提供了讀取二維數組、JSon 數據及Xml 文檔的三種數據解析器,分別用于把內存
中的二級數組、JSON 格式的數據及XML 文檔信息解析成記錄集。下面簡(jiǎn)單的介紹:
1
)ArrayReader
Ext.data.ArrayReader-數組解析器,用于讀取二維數組中的信息,并轉換成記錄集Record
對象。首先看下面的代碼:
這里定義的myReader 可以讀取下面的二維數組:
2
)JsonReader
Ext.data.JsonReader-Json 數據解析器,用于讀取JSON 格式的數據信息,并轉換成記
錄集Record 對象??聪旅媸褂?/span>JsonReader 的代碼:
var MyRecord = Ext.data.Record.create([
{name: 'title', mapping:1},
{name: 'username', mapping:2},
{name: 'loginTimes', type:3}
]);
var myReader = new Ext.data.ArrayReader({
id: 0
}, MyRecord);
[ [1, '測試', '小王',3], [2, '新年好', 'williamraym',13] ]
var MyRecord = Ext.data.Record.create([
{name: 'title'},
{name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'}
]);
var myReader = new Ext.data.JsonReader({
totalProperty: "results",
root: "rows",
id: "id"
}, MyRecord);
這里的JsonReader 可以解析下面的JSON 數據:
JSonReader 還有比較特殊的用法,就是可以把Store 中記錄集的配置信息存放直接保存
在從服務(wù)器端返回的JSON 數據中,比如下面的例子:
這一個(gè)不帶任何參數的myReader,可以處理從服務(wù)器端返回的下面JSON 數據:
3
)XmlReader
Ext.data.XmlReader-XML 文檔數據解析器,用于把XML 文檔數據轉換成記錄集Record
對象??聪旅娴拇a:
{ 'results': 2, 'rows': [
{ id: 1, title: '測試', author: '小王', loginTimes: 3 },
{ id: 2, title: 'Ben', author: 'williamraym', loginTimes:13} ]
}
var myReader = new Ext.data.JsonReader();
{
'metaData': {
totalProperty: 'results',
root: 'rows',
id: 'id',
fields: [
{name: 'title'},
{name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'} ]
},
'results': 2, 'rows': [
{ id: 1, title: '測試', author: '小王', loginTimes: 3 },
{ id: 2, title: '新年好', author: 'williamraym', loginTimes:13}]
}
var MyRecord = Ext.data.Record.create([
{name: 'title'},
{name: 'username', mapping: 'author'},
{name: 'loginTimes', type: 'int'}
]);
var myReader = new Ext.data.XmlReader({
totalRecords: "results",
record: "rows",
id: "id"
}, MyRecord);
上面的myReader 能夠解析下面的xml 文檔信息:
8.4
DataProxy
與自定義Stroe
DataProxy 字面解釋就是數據代理,也可以理解為數據源,也即從哪兒或如何得到需要
交給DataReader 解析的數據。數據代理(源)基類(lèi)由Ext.data.DataProxy 定義,在DataProxy
的基礎,ExtJS 提供了Ext.data.MemoryProxy、Ext.data.HttpProxy、Ext.data.ScriptTagProxy等三個(gè)分別用于從客戶(hù)端內存數據、Ajax 讀取服務(wù)器端的數據及從跨域服務(wù)器中讀取數據等三種實(shí)現。
比如像SimpleStore 等存儲器是直接從從客戶(hù)端的內存數組中讀取數據,此時(shí)就可以直
接使用Ext.data.MemoryProxy , 而大多數需要從服務(wù)器端加載的數據直接使用
Ext.data.HttpProxy,HttpProxy 直接使用Ext.Ajax 加載服務(wù)器的數據,由于這種請求是不能跨域的,所以要要讀取跨域服務(wù)器中的數據時(shí)就需要使用到Ext.data.ScriptTagProxy。
關(guān)于DataProxy 的更多內容,請參考http://wlr.easyjf.com 的VIP 文檔中的《ExtJS 數據
存儲Store 詳解》中的相關(guān)內容。
在實(shí)際應用中,除了基本的從內存中讀取javascript 數組對象,從服務(wù)器讀取JSON 數
組,從服務(wù)器取xml 文檔等形式的數據外,有時(shí)候還需要使用其它的數據讀取方式。比如
熟悉EasyJWeb 中遠程Web 腳本調用引擎或DWR 等框架的都知道,通過(guò)這些框架我們可以
直接在客戶(hù)端使用javascript 調用服務(wù)器端業(yè)務(wù)組件的方法,并把服務(wù)器端的結果返回到客戶(hù)端,客戶(hù)端得到的是一個(gè)javascript 對象或數組。由于這種方式的調用是異步的,因此,相對來(lái)說(shuō)有點(diǎn)特殊,即不能直接使用Ext.data.MemoryProxy , 也不能直接使用
Ext.data.HttpProxy,當然更不需要Ext.data.ScriptTagProxy,這時(shí)候就需要創(chuàng )建自定義的DataProxy 及Store,然后使用這個(gè)自定義的Store 來(lái)實(shí)現這種基于遠程腳本調用引擎的框架
<topics>
<results>2</results>
<row>
<id>1</id>
<title>測試</ title >
<author>小王</ author >
<loginTimes>3</ loginTimes >
</row>
<row>
<id>2</id>
<title>新年好</ title >
<author> williamraym </ author >
<loginTimes>13</ loginTimes >
</row>
</topics>
第九章、TreePanel
9.1、TreePanel之基本使用
在應用程序中,我們經(jīng)常會(huì )涉及到要顯示或處理樹(shù)狀結構的對象信息,比如部門(mén)信息、地區
信息,或者是樹(shù)狀的菜單信息,操作系統中的文件夾信息等。
對于傳統的html 頁(yè)面來(lái)說(shuō),要自己實(shí)現顯示樹(shù)比較困難,需要寫(xiě)很多的javascript,特
別是對于基于Ajax 異步加載的樹(shù)來(lái)說(shuō),不但涉及到Ajax 數據加載及處理技術(shù),還需要考慮
跨瀏覽器支持等,處理起來(lái)非常麻煩。ExtJS 中提供了現存的樹(shù)控件,通過(guò)這些控件可以在
B/S 應用中快速開(kāi)發(fā)出包含樹(shù)結構信息的應用。
TreePanel基本使用
樹(shù)控件由Ext.tree.TreePanel 類(lèi)定義,控件的名稱(chēng)為treepanel,TreePanel 類(lèi)繼承自Panel
面板。在ExtJS 中使用樹(shù)控件其實(shí)非常簡(jiǎn)單,我們先來(lái)看下面的代碼
代碼的第一句使用new Ext.tree.TreeNode 類(lèi)來(lái)創(chuàng )建一個(gè)樹(shù)節點(diǎn),第二句使用樹(shù)節點(diǎn)的
root 的appendChild 方法來(lái)往該節點(diǎn)中加入一個(gè)子節點(diǎn),最后直接使用new Ext.tree.TreePanel來(lái)創(chuàng )建一個(gè)樹(shù)面板,要樹(shù)面板的初始化參數中指定樹(shù)的root 屬性值為前面創(chuàng )建的root 節點(diǎn),也就是樹(shù)根節點(diǎn)。上面的程序執行效果如下圖所示:
樹(shù)的節點(diǎn)信息。ExtJS 的樹(shù)控件提供了對這種功能的支持,你只需要在創(chuàng )建樹(shù)控件的時(shí)
候,通過(guò)給樹(shù)指定一個(gè)節點(diǎn)加載器,可以用來(lái)從服務(wù)器端動(dòng)態(tài)加載樹(shù)的節點(diǎn)信息。我們來(lái)看
下面的代碼:
Ext.onReady(function(){
var root=new Ext.tree.TreeNode({
id:"root",
text:"樹(shù)的根"});
root.appendChild(new Ext.tree.TreeNode({
id:"c1",
text:"子節點(diǎn)"
}));
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
width:100
});
});
treedata.js 這個(gè)url 返回的內容如下:
執行上面的程序,可以得到一棵異步加載子節點(diǎn)的樹(shù),點(diǎn)擊“根節點(diǎn)”會(huì )到服務(wù)器端加
載子節點(diǎn),如下圖所示:
當然上面的程序是一次性加載完了樹(shù)的所有節點(diǎn)信息,我們也可以實(shí)現讓每一個(gè)節點(diǎn)都
支持動(dòng)態(tài)加載的樹(shù),只需要在通過(guò)服務(wù)器請求數據的時(shí)候,每次服務(wù)器端返回的數據只只包
含子節點(diǎn),而不用把孫子節點(diǎn)也返回即可。比如把上面treedata.js 中的內容改為下面的內容:
也就是節點(diǎn)樹(shù)中只包含一個(gè)子節點(diǎn),而該子節點(diǎn)通過(guò)指定leaf 值為false (默認情況該值
為false),表示該節點(diǎn)不是一個(gè)葉子節點(diǎn),其下面還有指節點(diǎn)。再執行前面的程序,不斷點(diǎn)
擊“子節點(diǎn)”可以得到如下圖所示的效果:
當然這是一個(gè)無(wú)限循環(huán)的樹(shù),在實(shí)際應用中我們服務(wù)器端返回的數據是程序動(dòng)態(tài)產(chǎn)生
var root=new Ext.tree.AsyncTreeNode({
id:"root",
text:"樹(shù)的根"});
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
loader: new Ext.tree.TreeLoader({url:"treedata.js"}),
width:100
});
[{
id: 1,
text: '子節點(diǎn)1',
leaf: true
},{
id: 2,
text: '兒子節點(diǎn)2',
children: [{
id: 3,
text: '孫子節點(diǎn)',
leaf: true
}]
}]
[{
id: 1,
text: '子節點(diǎn)',
leaf: false
}]
的,因此不可能每一次都產(chǎn)生leaf 為false 的節點(diǎn),如果是葉子節點(diǎn)的時(shí)候,則需要把返回
的JOSN 對象中的leaf 設置為true。如下所示:
事件處理
當然,僅僅能顯示一棵樹(shù)還不夠,我們一般還需要在用戶(hù)點(diǎn)擊樹(shù)節點(diǎn)的時(shí)候執行相應的
東西,比如打開(kāi)某一個(gè)連接,執行某一個(gè)函數等,這就需要使用到事件處理。比如下面的代
碼:
執行上面的程序,當用戶(hù)點(diǎn)擊樹(shù)控件中的任意節點(diǎn)時(shí),都會(huì )彈出一個(gè)提示信息框,當
用戶(hù)點(diǎn)擊c1 這個(gè)子節點(diǎn)時(shí),會(huì )彈出兩次提示信息框。因為我們除了指定tree 的click 事件響
應函數以外,另外又給node 節點(diǎn)指定單獨的事件響應函數。
當然,如果只是要實(shí)現當點(diǎn)擊樹(shù)節點(diǎn)時(shí)跳到某一個(gè)指定url 的功能則非常簡(jiǎn)單??聪旅?span lang="EN-US">
[{
id: 1,
text: '子節點(diǎn)',
leaf:true
}]
Ext.onReady(function(){
var root=new Ext.tree.TreeNode({
id:"root",
text:"樹(shù)的根"});
var c1=new Ext.tree.TreeNode({
id:"c1",
text:"子節點(diǎn)"
});
root.appendChild(c1);
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
width:100
});
tree.on("click",function(node,event){
alert("您點(diǎn)擊了"+node.text);
}
);
c1.on("click",function(node,event){
alert("您點(diǎn)擊了"+node.text);
}
);
});
的代碼:
執行程序,點(diǎn)擊樹(shù)節點(diǎn),將會(huì )在瀏覽新窗口中打開(kāi)節點(diǎn)中href 指定的鏈接。
9.2
TreeNode
在ExtJS 中,不管是葉子節點(diǎn)還是非葉子節點(diǎn),都統一用TreeNode 表表示樹(shù)的節點(diǎn)。
在ExtJS 中,有兩種類(lèi)型的樹(shù)節點(diǎn)。一種節點(diǎn)是普通的簡(jiǎn)單樹(shù)節點(diǎn),由Ext.tree.TreeNode 定
義,另外一種是需要異步加載子節點(diǎn)信息的樹(shù)節點(diǎn),該類(lèi)由Ext.tree.AsyncTreeNode 定義???span lang="EN-US">
下面的代碼:
執行程序,點(diǎn)擊樹(shù)中的“根節點(diǎn)”則會(huì )一直發(fā)現樹(shù)會(huì )嘗試加載這個(gè)節點(diǎn)的子節點(diǎn),由這
Ext.onReady(function(){
var root=new Ext.tree.TreeNode({
id:"root",
href:"http://www.easyjf.com",
hrefTarget:"_blank",
text:"樹(shù)的根"});
var c1=new Ext.tree.TreeNode({
id:"c1",
href:"http://wlr.easyjf.com",
hrefTarget:"_blank",
text:"子節點(diǎn)"
});
root.appendChild(c1);
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
width:100
});
});
Ext.onReady(function(){
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:new Ext.tree.AsyncTreeNode({
text:"根節點(diǎn)"
}),
width:100
});
});
里沒(méi)有指定樹(shù)的加載器,所以“根節點(diǎn)”會(huì )變成一直處于加載的狀態(tài)。如下圖所示:
對于普通的TreeNode 來(lái)說(shuō),可以通過(guò)調用節點(diǎn)的appendChild、removeChild 等方法來(lái)
往該節點(diǎn)中加入子節點(diǎn)或刪除子節點(diǎn)等操作。
TreeNode 與AsyncTreeNode 可以同時(shí)使用,比如下面的代碼:
treedata.js 中的內容仍然是:
執行上面的程序可以得到一棵如下圖所示的樹(shù):
Ext.onReady(function(){
var root=new Ext.tree.TreeNode({
id:"root",
text:"樹(shù)的根"
});
var c1=new Ext.tree.TreeNode({
text:"子節點(diǎn)1"
})
var c2=new Ext.tree.AsyncTreeNode({
text:"子節點(diǎn)2"
});
root.appendChild(c1);
root.appendChild(c2);
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
width:300,
loader:new Ext.tree.TreeLoader({
applyLoader:false,
url:"treedata.js"
})
});
});
[{
id: 1,
text: '子節點(diǎn)'
}]
另外要在樹(shù)以外的程序中得到當前選擇的節點(diǎn),可以通過(guò)TreePanel 的
getSelectionModel 方法來(lái)獲得,該方法默認返回的是Ext.tree.DefaultSelectionModel 對象,
DefaultSelectionModel 的getSelectedNode 方法返回當前選擇的樹(shù)節點(diǎn)。比如要得到樹(shù)tree 中
中當前選擇節點(diǎn),代碼如下:
9.3
TreeLoader
對于ExtJS 中的樹(shù)來(lái)說(shuō),樹(shù)加載器TreeLoader 是一個(gè)比較關(guān)鍵的部件,樹(shù)加載器由
Ext.tree.TreeLoader 類(lèi)定義,只有AsyncTreeNode 才會(huì )使用TreeLoader??聪旅娴拇a:
首先我們使用Ext.tree.TreeLoader 來(lái)初始化了一個(gè)TreeLoader 對象,構造函數中的配置
參數url 表示獲得樹(shù)節點(diǎn)信息的url 。然后在初始化根節點(diǎn)的時(shí)候我們使用的是
AsyncTreeNode,在該節點(diǎn)中指定該節點(diǎn)的laoder 為前面定義的loader。執行這段程序,在
點(diǎn)擊“根節點(diǎn)”時(shí),會(huì )從服務(wù)器端指定root 節點(diǎn)的子節點(diǎn)信息。
TreeLoader 嚴格來(lái)說(shuō)是針對樹(shù)的節點(diǎn)來(lái)定義的,可以給樹(shù)中的每一個(gè)節點(diǎn)定義不同的
TreeLoader,默認情況下,如果一個(gè)AsyncTreeNode 節點(diǎn)在準備加載子節點(diǎn)的時(shí)候,如果該
節點(diǎn)上沒(méi)有定義loader,則會(huì )使用TreePanel 中定義的loader 作為加載器。因此,我們可以
直接在TreePanel 上面指定loader 屬性,這樣就不需要給每一個(gè)節點(diǎn)指定具體的TreeLoader
了。因此,上面的代碼可以改成如下所示的內容:
tree.getSelectionModel().getSelectedNode()
Ext.onReady(function(){
var loader=new Ext.tree.TreeLoader({
url:"treedata.js"
});
var root=new Ext.tree.AsyncTreeNode({
id:"root",
text:"根節點(diǎn)",
loader:loader});
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
width:100
});
});
9.4
自定義TreeLoader
在ExtJS 自己的TreeLoader 中,當要實(shí)現從遠程服務(wù)器端異步加載樹(shù)節點(diǎn)信息的時(shí)候,
都是通過(guò)請求服務(wù)器上的某一個(gè)URL 來(lái)進(jìn)行的,這個(gè)URL 返回下面的信息:
假如我們是直接通過(guò)類(lèi)似DWR 或EasyJWeb 的遠程腳本引擎在客戶(hù)端直接調用服務(wù)器
的業(yè)務(wù)方法,直接跳過(guò)了WEB(不需要Struts、JSP 或其它Web 層的代碼)這一層,這時(shí)
我們沒(méi)有URL,這時(shí)該怎么辦呢?這就需要使用到自定義的TreeLoader,下面我們通過(guò)一
個(gè)實(shí)例來(lái)做簡(jiǎn)單的講解。
看服務(wù)器端的ITopicCategoryService
loadCategory 方法返回一個(gè)類(lèi)型為Node 的列表,也就是返回指定id 的下級分類(lèi)信節點(diǎn)
信息,Node 對應樹(shù)節點(diǎn)的信息,代碼如下:
[{
id: 1,
text: 'A leaf Node',
leaf: true
},{
id: 2,
text: 'A folder Node',
children: [{
id: 3,
text: 'A child Node',
leaf: true
}]
}]
public interface ITopicCategoryService {
List loadCategory(Long id);
}
public class Node {
private TopicCategory category;
Node(TopicCategory category) {
this.category = category;
}
public String getId() {
return category.getId().toString();
}
public boolean getLeaf() {
Node 在這里相當于一個(gè)簡(jiǎn)單適配器,其實(shí)就是把數據庫中的日志分類(lèi)實(shí)體適配成包樹(shù)
節點(diǎn)對象。把ITopicCategoryService 發(fā)布成可供客戶(hù)端遠程調用,使用EasyJWeb 的話(huà)引如下面三個(gè)js:
使用DWR 的話(huà)引入下面的兩個(gè)js:
這樣我們可以在頁(yè)使用下面的javascrpt 來(lái)從服務(wù)器端獲得某一個(gè)節點(diǎn)的子節點(diǎn)信息,
代碼如下:
如何讓ExtJS 的樹(shù)面板能通過(guò)這個(gè)遠程web 腳本方法topicCategoryService.loadCategory
來(lái)加載異步加載樹(shù)節點(diǎn)信息呢?其實(shí)很簡(jiǎn)單,跟一般的使用沒(méi)什么兩樣,樹(shù)面板TreePanel
的代碼如下:
return category.getChildren().size() < 1;
}
public String getText() {
return category.getName();
}
public String getQtip() {
return category.getName();
}
}
<script type="text/javascript" src="/ejf/easyajax/prototype.js"></script>
<script type="text/javascript" src="/ejf/easyajax/engine.js"></script>
<script type="text/javascript" src="/ejf/easyajax/topicCategoryService.js"></script>
<script type="text/javascript" src="/dwr/dwr/engine.js "></script>
<script type="text/javascript" src="/dwr/dwr/util.js "></script>
<script type="text/javascript" src="/dwr/dwr/interface/ topicCategoryService.js "></script>
function test()
{
topicCategoryService.loadCategory(1,function(ret)
{
alert("一共有"+ret.length+"個(gè)子節點(diǎn)");
}
}
然后區別是在loader 部分,使用遠程Web 調用來(lái)加載樹(shù)節點(diǎn)的loader,代碼如下:
再回顧一下傳統的直接通過(guò)url 加載樹(shù)節點(diǎn)的TreeLoader 代碼,如下所示:
區別在于,遠程腳本調用方式加載樹(shù)節點(diǎn)信息使用的是WebInvokeTreeLoader,需要通
過(guò)fn 屬性來(lái)指定用于加載數據的遠程方法,并在beforeload 事件處理器設置參數遠程方法
調用的參數值。而傳統的樹(shù)節點(diǎn)加載器是Ext.tree.TreeLoader,需要指定一個(gè)url 來(lái)獲得json數據。WebInvokeTreeLoader 是自定義的樹(shù)加載器,代碼其實(shí)比較簡(jiǎn)單,你可以自己寫(xiě)一個(gè)。本方案僅供參考,關(guān)于WebInvokeTreeLoader 的源代碼我已經(jīng)傳到了我用ExtJS 開(kāi)發(fā)的Blog示例網(wǎng)站上了,僅供VIP 會(huì )員瀏覽,有興趣的朋友可跟我聯(lián)系。
var tree = new Ext.tree.TreePanel({
autoScroll:true,
animate:true,
width:'100px',
height:'300px',
enableDD:true,
containerScroll: true,
loader: loader
root: new Ext.tree.AsyncTreeNode({
text: '日志分類(lèi)',
id:'root'
});
});
var loader=new WebInvokeTreeLoader({
fn:topicCategoryService.loadCategory
});
loader.on("beforeload",function(l,node){
l.args[0]=(node.id!='root'?node.id:"-1");
});
var loader=new Ext.tree.TreeLoader({
url:'/topicCategory.ejf?cmd=getCategory&pageSize=-1&treeData=true'
});
loader.on("beforeloader",function(loader,node){
loader.baseParams.id=(node.id!='root'?node.id:"");
});__
聯(lián)系客服