Ext.data.Store是EXT中用來(lái)進(jìn)行數(shù)據(jù)交換和數(shù)據(jù)交互的標(biāo)準(zhǔn)中間件,無(wú)論是Grid還是ComboBox,都是通過(guò)它實(shí)現(xiàn)數(shù)據(jù)讀取、類型轉(zhuǎn)換、排序分頁(yè)和搜索等操作的。
Ext.data.Store中有一個(gè)Ext.data.Record數(shù)組,所有數(shù)據(jù)都存放在這些Ext.data. Record實(shí)例中,為后面的讀取和修改操作做準(zhǔn)備。
Ext.data.Store的基本用法
在使用之前,首先要?jiǎng)?chuàng)建一個(gè)Ext.data.Store的實(shí)例,如下面的代碼所示。
- var data = [
- ['boy', 0],
- ['girl', 1]
- ];
-
- var store = new Ext.data.Store({
- proxy: new Ext.data.MemoryProxy(data),
- reader: new Ext.data.ArrayReader({}, PersonRecord)
- });
-
- store.load();
- var data = [
- ['boy', 0],
- ['girl', 1]
- ];
-
- var store = new Ext.data.Store({
- proxy: new Ext.data.MemoryProxy(data),
- reader: new Ext.data.ArrayReader({}, PersonRecord)
- });
-
- store.load();
每個(gè)store最少需要兩個(gè)組件的支持,分別是proxy和reader,proxy用于從某個(gè)途徑讀取原始數(shù)據(jù),reader用于將原始數(shù)據(jù)轉(zhuǎn)換成Record實(shí)例。
這里我們使用的是Ext.data.MemoryProxy和Ext.data.ArrayReader,將data數(shù)組中的數(shù)據(jù)轉(zhuǎn)換成對(duì)應(yīng)的幾個(gè)PersonRecord實(shí)例,然后放入store中。
store創(chuàng)建完畢之后,執(zhí)行store.load()實(shí)現(xiàn)這個(gè)轉(zhuǎn)換過(guò)程。
經(jīng)過(guò)轉(zhuǎn)換之后,store里的數(shù)據(jù)就可以提供給Grid或ComboBox使用了,這就是Ext.data. Store的最基本用法。
Ext.data.Store對(duì)數(shù)據(jù)進(jìn)行排序
Ext.data.Store提供了一系列屬性和函數(shù),利用它們對(duì)數(shù)據(jù)進(jìn)行排序操作。
可以在創(chuàng)建Ext.data.Store時(shí)使用sortInfo參數(shù)指定排序的字段和排序方式,如下面的代碼所示。
- var store = new Ext.data.Store({
- proxy: new Ext.data.MemoryProxy(data),
- reader: new Ext.data.ArrayReader({}, PersonRecord),
- sortInfo: {field: 'name', direction: 'DESC'}
- });
- var store = new Ext.data.Store({
- proxy: new Ext.data.MemoryProxy(data),
- reader: new Ext.data.ArrayReader({}, PersonRecord),
- sortInfo: {field: 'name', direction: 'DESC'}
- });
這樣,在store加載數(shù)據(jù)之后,就會(huì)自動(dòng)根據(jù)name字段進(jìn)行降序排列。對(duì)store使用store.setDefaultSort('name','DESC');也會(huì)達(dá)到同樣效果。
也可以在任何時(shí)候調(diào)用sort()函數(shù),比如store.sort('name', 'DESC');,對(duì)store中的數(shù)據(jù)進(jìn)行排序。
如果我們希望獲得store的排序信息,可以調(diào)用getSortState()函數(shù),返回的是類似{field: "name", direction: " DESC"}的JSON對(duì)象。
與排序相關(guān)的參數(shù)還有remoteSort,這個(gè)參數(shù)是用來(lái)實(shí)現(xiàn)后臺(tái)排序功能的。
當(dāng)設(shè)置為remoteSort:true時(shí),store會(huì)在向后臺(tái)請(qǐng)求數(shù)據(jù)時(shí)自動(dòng)加入sort和dir兩個(gè)參數(shù),
分別對(duì)應(yīng)排序的字段和排序的方式,由后臺(tái)獲取并處理這兩個(gè)參數(shù),在后臺(tái)對(duì)所需數(shù)據(jù)進(jìn)行排序操作。
remoteSort:true也會(huì)導(dǎo)致每次執(zhí)行sort()時(shí)都要去后臺(tái)重新加載數(shù)據(jù),而不能只對(duì)本地?cái)?shù)據(jù)進(jìn)行排序。
Ext.data.Store從store中獲取數(shù)據(jù)
從store中獲取數(shù)據(jù)有很多種途徑,可以依據(jù)不同的要求選擇不同的函數(shù)。
最直接的方法是根據(jù)record在store中的行號(hào)獲得對(duì)應(yīng)的record,得到了record就可以使用get()函數(shù)獲得里面的數(shù)據(jù)了,如下面的代碼所示。
- store.getAt(0).get('name')
- store.getAt(0).get('name')
通過(guò)這種方式,我們可以遍歷store中所有的record,依次得到它們的數(shù)據(jù),如下面的代碼所示。
- for (var i = 0; i < store.getCount(); i++) {
- var record = store.getAt(i);
- alert(record.get('name'));
- }
- for (var i = 0; i < store.getCount(); i++) {
- var record = store.getAt(i);
- alert(record.get('name'));
- }
Store.getCount()返回的是store中的所有數(shù)據(jù)記錄,然后使用for循環(huán)遍歷整個(gè)store,從而得到每條記錄。
除了使用getCount()的方法外,還可以使用each()函數(shù),如下面的代碼所示。
- store.each(function(record) {
- alert(record.get('name'));
- });
- store.each(function(record) {
- alert(record.get('name'));
- });
Each()可以接受一個(gè)函數(shù)作為參數(shù),遍歷內(nèi)部record,并將每個(gè)record作為參數(shù)傳遞給function()處理。
如果希望停止遍歷,可以讓function()返回false。
也可以使用getRange()函數(shù)連續(xù)獲得多個(gè)record,只需要指定開(kāi)始和結(jié)束位置的索引值,如下面的代碼所示。
- var records = store.getRange(0, 1);
-
- for (var i = 0; i < records.length; i++) {
- var record = records[i];
- alert(record.get('name'));
- }
- var records = store.getRange(0, 1);
-
- for (var i = 0; i < records.length; i++) {
- var record = records[i];
- alert(record.get('name'));
- }
如果確實(shí)不知道record的id,也可以根據(jù)record本身的id從store中獲得對(duì)應(yīng)的record,如下面的代碼所示。
- store.getById(1001).get('name')
- store.getById(1001).get('name')
EXT還提供了函數(shù)find()和findBy(),可以利用它們對(duì)store中的數(shù)據(jù)進(jìn)行搜索,如下面的代碼所示。
- find( String property, String/RegExp value, [Number startIndex], [Boolean anyMatch],[Boolean caseSensitive] )
- find( String property, String/RegExp value, [Number startIndex], [Boolean anyMatch],[Boolean caseSensitive] )
在這5個(gè)參數(shù)中,只有前兩個(gè)是必須的。
第一個(gè)參數(shù)property代表搜索的字段名;
第二個(gè)參數(shù)value是匹配用字符串或正則表達(dá)式;
第三個(gè)參數(shù)startIndex表示從第幾行開(kāi)始搜索;
第四個(gè)參數(shù)anyMatch為true時(shí),不必從頭開(kāi)始匹配;
第五個(gè)參數(shù)caseSensitive為true時(shí),會(huì)區(qū)分大小寫(xiě)。
如下面的代碼所示:
- var index = store.find('name','g');
-
- alert(store.getAt(index).get('name'));
- var index = store.find('name','g');
-
- alert(store.getAt(index).get('name'));
與find()函數(shù)對(duì)應(yīng)的findBy()函數(shù)的定義格式如下:
- findBy( Function fn, [Object scope], [Number startIndex] ) : Number
- findBy( Function fn, [Object scope], [Number startIndex] ) : Number
findBy()函數(shù)允許用戶使用自定義函數(shù)對(duì)內(nèi)部數(shù)據(jù)進(jìn)行搜索。
fn返回true時(shí),表示查找成功,于是停止遍歷并返回行號(hào)。
fn返回false時(shí),表示查找失敗(即未找到),繼續(xù)遍歷,如下面的代碼所示。
- index = store.findBy(function(record, id) {
- return record.get('name') == 'girl' && record.get('sex') == 1;
- });
-
- alert(store.getAt(index).get('name'));
- index = store.findBy(function(record, id) {
- return record.get('name') == 'girl' && record.get('sex') == 1;
- });
-
- alert(store.getAt(index).get('name'));
通過(guò)findBy()函數(shù),我們可以同時(shí)判斷record中的多個(gè)字段,在函數(shù)中實(shí)現(xiàn)復(fù)雜邏輯。
我們還可以使用query和queryBy函數(shù)對(duì)store中的數(shù)據(jù)進(jìn)行查詢。
與find和findBy不同的是,query和queryBy返回的是一個(gè)MixCollection對(duì)象,里面包含了搜索得到的數(shù)據(jù),如下面的代碼所示。
- alert(store.query('name', 'boy'));
-
- alert(store.queryBy(function(record) {
- return record.get('name') == 'girl' && record.get('sex') == 1;
- }));
- alert(store.query('name', 'boy'));
-
- alert(store.queryBy(function(record) {
- return record.get('name') == 'girl' && record.get('sex') == 1;
- }));
Ext.data.Store更新store中的數(shù)據(jù)
可以使用add(Ext.data.Record[] records)向store末尾添加一個(gè)或多個(gè)record,使用的參數(shù)可以是一個(gè)record實(shí)例,如下面的代碼所示。
- store.add(new PersonRecord({
- name: 'other',
- sex: 0
- }));
- store.add(new PersonRecord({
- name: 'other',
- sex: 0
- }));
Add()的也可以添加一個(gè)record數(shù)組,如下面的代碼所示:
- store.add([new PersonRecord({
- name: 'other1',
- sex: 0
- }), new PersonRecord({
- name: 'other2',
- sex: 0
- })]);
- store.add([new PersonRecord({
- name: 'other1',
- sex: 0
- }), new PersonRecord({
- name: 'other2',
- sex: 0
- })]);
Add()函數(shù)每次都會(huì)將新數(shù)據(jù)添加到store的末尾,這就有可能破壞store原有的排序方式。如果希望根據(jù)store原來(lái)的排序方式將新數(shù)據(jù)插入到對(duì)應(yīng)的位置,可以使用addSorted()函數(shù)。它會(huì)在添加新數(shù)據(jù)之后立即對(duì)store進(jìn)行排序,這樣就可以保證store中的數(shù)據(jù)有序地顯示,如下面的代碼所示。
- store.addSorted(new PersonRecord({
- name: 'lili',
- sex: 1
- }));
- store.addSorted(new PersonRecord({
- name: 'lili',
- sex: 1
- }));
store會(huì)根據(jù)排序信息查找這條record應(yīng)該插入的索引位置,然后根據(jù)得到的索引位置插入數(shù)據(jù),從而實(shí)現(xiàn)對(duì)整體進(jìn)行排序。這個(gè)函數(shù)需要預(yù)先為store設(shè)置本地排序,否則會(huì)不起作用。
如果希望自己指定數(shù)據(jù)插入的索引位置,可以使用insert()函數(shù)。它的第一個(gè)參數(shù)表示插入數(shù)據(jù)的索引位置,可以使用record實(shí)例或record實(shí)例的數(shù)組作為參數(shù),插入之后,后面的數(shù)據(jù)自動(dòng)后移,如下面的代碼所示。
- store.insert(3, new PersonRecord({
- name: 'other',
- sex: 0
- }));
-
- store.insert(3, [new PersonRecord({
- name: 'other1',
- sex: 0
- }), new PersonRecord({
- name: 'other2',
- sex: 0
- })]);
- store.insert(3, new PersonRecord({
- name: 'other',
- sex: 0
- }));
-
- store.insert(3, [new PersonRecord({
- name: 'other1',
- sex: 0
- }), new PersonRecord({
- name: 'other2',
- sex: 0
- })]);
刪除操作可以使用remove()和removeAll()函數(shù),它們分別可以刪除指定的record和清空整個(gè)store中的數(shù)據(jù),如下面的代碼所示。
- store.remove(store.getAt(0));
- store.removeAll();
- store.remove(store.getAt(0));
- store.removeAll();
store中沒(méi)有專門(mén)提供修改某一行record的操作,我們需要先從store中獲取一個(gè)record。對(duì)這個(gè)record內(nèi)部數(shù)據(jù)的修改會(huì)直接反映到store上,如下面的代碼所示。
- store.getAt(0).set('name', 'xxxx');
- store.getAt(0).set('name', 'xxxx');
修改record的內(nèi)部數(shù)據(jù)之后有兩種選擇:執(zhí)行rejectChanges()撤銷(xiāo)所有修改,將修改過(guò)的record恢復(fù)到原來(lái)的狀態(tài);執(zhí)行commitChanges()提交數(shù)據(jù)修改。在執(zhí)行撤銷(xiāo)和提交操作之前,可以使用getModifiedRecords()獲得store中修改過(guò)的record數(shù)組。
與修改數(shù)據(jù)相關(guān)的參數(shù)是pruneModifiedRecords,如果將它設(shè)置為true,當(dāng)每次執(zhí)行刪除或reload操作時(shí),都會(huì)清空所有修改。這樣,在每次執(zhí)行刪除或reload操作之后,getModifiedRecords()返回的就是一個(gè)空數(shù)組,否則仍然會(huì)得到上次修改過(guò)的record記錄
Ext.data.Store加載及顯示數(shù)據(jù)
store創(chuàng)建好后,需要調(diào)用load()函數(shù)加載數(shù)據(jù),加載成功后才能對(duì)store中的數(shù)據(jù)進(jìn)行操作。load()調(diào)用的完整過(guò)程如下面的代碼所示。
- store.load({
- params: {start:0,limit:20},
- callback: function(records, options, success){
- Ext.Msg.alert('info', '加載完畢');
- },
- scope: store,
- add: true
- });
- store.load({
- params: {start:0,limit:20},
- callback: function(records, options, success){
- Ext.Msg.alert('info', '加載完畢');
- },
- scope: store,
- add: true
- });
1. params是在store加載時(shí)發(fā)送的附加參數(shù)。
2. callback是加載完畢時(shí)執(zhí)行的回調(diào)函數(shù),它包含3個(gè)參數(shù):records參數(shù)表示獲得的數(shù)據(jù),options表示執(zhí)行l(wèi)oad()時(shí)傳遞的參數(shù),success表示是否加載成功。
3. Scope用來(lái)指定回調(diào)函數(shù)執(zhí)行時(shí)的作用域。
4. Add為true時(shí),load()得到的數(shù)據(jù)會(huì)添加在原來(lái)的store數(shù)據(jù)的末尾,否則會(huì)先清除之前的數(shù)據(jù),再將得到的數(shù)據(jù)添加到store中。
一般來(lái)說(shuō),為了對(duì)store中的數(shù)據(jù)進(jìn)行初始化,load()函數(shù)只需要執(zhí)行一次。如果用params參數(shù)指定了需要使用的參數(shù),以后再次執(zhí)行reload()重新加載數(shù)據(jù)時(shí),store會(huì)自動(dòng)使用上次load()中包含的params參數(shù)內(nèi)容。
如果有一些需要固定傳遞的參數(shù),也可以使用baseParams參數(shù)執(zhí)行,它是一個(gè)JSON對(duì)象,里面的數(shù)據(jù)會(huì)作為參數(shù)發(fā)送給后臺(tái)處理,如下面的代碼所示。
- store.baseParams.start = 0;
- store.baseParams.limit = 20;
- store.baseParams.start = 0;
- store.baseParams.limit = 20;
為store加載數(shù)據(jù)之后,有時(shí)不需要把所有數(shù)據(jù)都顯示出來(lái),這時(shí)可以使用函數(shù)filter和filterBy對(duì)store中的數(shù)據(jù)進(jìn)行過(guò)濾,只顯示符合條件的部分,如下面的代碼所示。
- filter( String field, String/RegExp value, [Boolean anyMatch], [Boolean caseSensitive] ) : void
- filter( String field, String/RegExp value, [Boolean anyMatch], [Boolean caseSensitive] ) : void
filter()函數(shù)的用法與之前談到的find()相似,如下面的代碼所示。
- store.filter('name', 'boy');
- store.filter('name', 'boy');
對(duì)應(yīng)的filterBy()與findBy()類似,也可以在自定義的函數(shù)中實(shí)現(xiàn)各種復(fù)雜判斷,如下面的代碼所示。
- store.filterBy(function(record) {
- return record.get('name') == 'girl' && record.get('sex') == 1;
- });
- store.filterBy(function(record) {
- return record.get('name') == 'girl' && record.get('sex') == 1;
- });
如果想取消過(guò)濾并顯示所有數(shù)據(jù),那么可以調(diào)用clearFilter()函數(shù),如下面的代碼所示。
如果想知道store上是否設(shè)置了過(guò)濾器,可以通過(guò)isFiltered()函數(shù)進(jìn)行判斷。
Ext.data.Store其他功能
除了上面提到的數(shù)據(jù)獲取、排序、更新、顯示等功能外,store還提供了其他一些功能函數(shù)。
- collect( String dataIndex, [Boolean allowNull], [Boolean bypassFilter] ) : Array
- collect( String dataIndex, [Boolean allowNull], [Boolean bypassFilter] ) : Array
collect函數(shù)獲得指定的dataIndex對(duì)應(yīng)的那一列的數(shù)據(jù),當(dāng)allowNull參數(shù)為true時(shí),返回的結(jié)果中可能會(huì)包含null、undefined或空字符串,否則collect函數(shù)會(huì)自動(dòng)將這些空數(shù)據(jù)過(guò)濾掉。當(dāng)bypassFilter參數(shù)為true時(shí),collect的結(jié)果不會(huì)受查詢條件的影響,無(wú)論查詢條件是什么都會(huì)忽略掉,返回的信息是所有的數(shù)據(jù),如下面的代碼所示。
- alert(store.collect('name'));
- alert(store.collect('name'));
這樣會(huì)獲得所有name列的值,示例中返回的是包含了'boy'和'girl'的數(shù)組。
getTotalCount()用于在翻頁(yè)時(shí)獲得后臺(tái)傳遞過(guò)來(lái)的數(shù)據(jù)總數(shù)。如果沒(méi)有設(shè)置翻頁(yè),get- TotalCount()的結(jié)果與getCount()相同,都是返回當(dāng)前的數(shù)據(jù)總數(shù),如下面的代碼所示。
- alert(store.getTotalCount());
- alert(store.getTotalCount());
indexOf(Ext.data.Record record)和indexOfId(String id)函數(shù)根據(jù)record或record的id獲得record對(duì)應(yīng)的行號(hào),如下面的代碼所示。
- alert(store.indexOf(store.getAt(1)));
- alert(store.indexOfId(1001));
- alert(store.indexOf(store.getAt(1)));
- alert(store.indexOfId(1001));
loadData(object data, [Boolean append])從本地JavaScript變量中讀取數(shù)據(jù),append為true時(shí),將讀取的數(shù)據(jù)附加到原數(shù)據(jù)后,否則執(zhí)行整體更新,如下面的代碼所示。
- store.loadData(data, true);
- store.loadData(data, true);
Sum(String property, Number start, Number end):Number用于計(jì)算某一個(gè)列從start到end的總和,如下面的代碼所示。
如果省略參數(shù)start和end,就計(jì)算全部數(shù)據(jù)的總和。
store還提供了一系列事件(見(jiàn)下表),讓我們可以為對(duì)應(yīng)操作設(shè)定操作函數(shù)。
表 store提供的事件
事件名
|
參 數(shù)
|
add
|
( Store this, Ext.data.Record[] records, Number index )
|
beforelaod
|
( Store this, Object options )
|
clear
|
( Store this )
|
datachanged
|
( Store this )
|
load
|
( Store this, Ext.data.Record[] records, Object options )
|
loadexception
|
()
|
metachange
|
( Store this, Object meta. )
|
remove
|
( Store this, Ext.data.Record record, Number index )
|
update
|
( Store this, Ext.data.Record record, String operation )
|
至此,store和record等組件已經(jīng)講解完畢,下面我們主要討論一下常用的proxy和reader組件。