嘿,別看關(guān)鍵就在這兒,事實(shí)上,它的代碼很少的哦。加上注釋才219行。研究研究。
有個(gè)事要說(shuō)一下:DataProxy的子類呢,都有一個(gè)load來(lái)加載數(shù)據(jù),DataReader的子類呢,都有一個(gè)read來(lái)讀取數(shù)據(jù)。
而Ext.data.JsonReader有兩個(gè)關(guān)鍵函數(shù):read、readRecords。好了。來(lái)研究一下。
Ext.data.JsonReader = function(meta, recordType){
meta = meta || {};
Ext.data.JsonReader.superclass.constructor.call(this, meta, recordType || meta.fields);
};
這是構(gòu)造函數(shù)。簡(jiǎn)單。meta是數(shù)據(jù)格式定義,recordType是記錄類型。其中recordType可以是一個(gè)定義記錄的數(shù)組,也可以不傳,而把記錄的各個(gè)字段的定義放到meta中的fields字段中。且看它對(duì)父類構(gòu)造函數(shù)的調(diào)用:
Ext.data.DataReader = function(meta, recordType){
this.meta = meta;
this.recordType = Ext.isArray(recordType) ?
Ext.data.Record.create(recordType) : recordType;
};
Ext.data.DataReader.prototype = { };
這下全明白了吧。recordType可以是記錄類型,可以是字段定義數(shù)組,還可以不傳。
所以,構(gòu)造函數(shù)就是定義兩個(gè)屬性:meta、recordType。這兩東西后面有用。
這個(gè)meta、recordType組成如何?這個(gè)必須說(shuō)明,不然,這個(gè)類也就沒(méi)法用了。
meta:
totalProperty json數(shù)據(jù)中,保存總記錄數(shù)的屬性
successProperty json數(shù)據(jù)中,保存是否返回成功的屬性名
root json數(shù)據(jù)中,保存記錄集的屬性的屬性名
id json數(shù)據(jù)中,記錄中主鍵所對(duì)應(yīng)的列的屬性名
recordType:
這個(gè)東西,事實(shí)上要去看Ext.data.Record的create函數(shù)的文檔,我且把它翻譯一下,如下:
create( [Array o] ) : function
創(chuàng)建包含指定字段結(jié)構(gòu)的繼承自Ext.data.Record的類。靜態(tài)方法。
參數(shù):
o : Array
一個(gè)定義記錄結(jié)構(gòu)的字段信息數(shù)組。每個(gè)數(shù)組元素包含name,其他可選的有:mapping、type。通過(guò)它們,可以讓Ext.data.Reader從一個(gè)數(shù)據(jù)對(duì)象中獲取各字段的值。每個(gè)字段定義對(duì)象都可能包含如下屬性:
name : String
在記錄中標(biāo)志一個(gè)字段的名字。它通常用于引用指定字段,例如,在定義Ext.grid.ColumnModel的dataIndex屬性時(shí),要傳過(guò)去的。
mapping : String
當(dāng)在Ext.data.Reader中創(chuàng)建記錄時(shí),如何將json對(duì)象中指定屬性值映射到此字段。
type : String
字段的類型,可能值為:
auto(默認(rèn)值,沒(méi)有任何轉(zhuǎn)化)、string、int、float、boolean、date
sortType : Mixed
Ext.data.SortTypes中的一個(gè)成員。
sortDir : String
排序方式,"ASC"或者"DESC"。
convert : Function
如果要對(duì)這個(gè)字段的值進(jìn)行一些物殊處理,這時(shí)需要一個(gè)能定制的回調(diào),用它來(lái)手工處理值。它的參數(shù)如下:
v : Mixed
通過(guò)mapping映射找到的值。已從json中取出來(lái)的。
rec : Mixed
在json中的,對(duì)應(yīng)于此記錄的json對(duì)象。
dateFormat : String
用于Date.parseDate函數(shù)的格式化字符串。
defaultValue : Mixed
當(dāng)字段值在原數(shù)據(jù)中不存在時(shí)所取的默認(rèn)值,默認(rèn)為空字符串。
用法:
var TopicRecord = Ext.data.Record.create([
{name: 'title', mapping: 'topic_title'},
{name: 'author', mapping: 'username'},
{name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
{name: 'lastPost', mapping: 'post_time', type: 'date'},
{name: 'lastPoster', mapping: 'user2'},
{name: 'excerpt', mapping: 'post_text'}
]);
var myNewRecord = new TopicRecord({
title: 'Do my job please',
author: 'noobie',
totalPosts: 1,
lastPost: new Date(),
lastPoster: 'Animal',
excerpt: 'No way dude!'
});
myStore.add(myNewRecord);
不過(guò),JsonReader有一些細(xì)節(jié)問(wèn)題,還要細(xì)究。待某家一一道來(lái)。
構(gòu)造函數(shù)已講,下面依代碼順序講解了。
read : function(response){
var json = response.responseText;
var o = eval("("+json+")");
if(!o) {
throw {message: "JsonReader.read: Json object not found"};
}
return this.readRecords(o);
},
這個(gè)是整個(gè)JsonReader的關(guān)鍵所在了。君可找到Ext.data.HttpProxy中的loadResponse函數(shù),里面有這么一行代碼:
result = o.reader.read(response);
可見(jiàn),是proxy里面調(diào)用reader.read方法才得以取出結(jié)果集的。這是要表明:read乃JsonReader三軍中軍之所在。 read又調(diào)用readRecords,read把json字符串轉(zhuǎn)化為對(duì)象然后交給readRecords。這個(gè)本無(wú)不妥,但是,asp.net中,它的結(jié)果有點(diǎn)曲折,結(jié)果是放在o.d中,而不能直接從o中取得。所以,事實(shí)上應(yīng)當(dāng)這么寫(xiě):this.readRecords(o.d)。 這就成了。繼續(xù)往下面看:
onMetaChange : function(meta, recordType, o){
}
這個(gè)函數(shù)說(shuō)是要由store實(shí)現(xiàn)的,現(xiàn)在不知道它的用處。還往下看:
simpleAccess: function(obj, subsc) {
return obj[subsc];
},
getJsonAccessor: function(){
var re = /[/[/.]/;
return function(expr) {
try {
return(re.test(expr))
? new Function("obj", "return obj." + expr)
: function(obj){
return obj[expr];
};
} catch(e){}
return Ext.emptyFn;
};
}(),
取一對(duì)象的屬性有兩種方法,前面都已提及:
一、obj.xxxx
二、obj[xxxx]
這兩種都行。但是,如果傳過(guò)來(lái)一個(gè)對(duì)象,已知其對(duì)象的引用obj,但是有的只是它的屬性名的字符串,這時(shí)就可以用第二種方法取出,但是,如屬性名中含[],那么就不大方便了,又或者是屬性又帶屬性,這事也只能用第一種方法。這兩個(gè)函數(shù)正是為事而來(lái)。且看那getJsonAccessor,著實(shí)巧妙,函數(shù)返回一函數(shù),這不是巧妙之處,這個(gè)我以前就見(jiàn)識(shí)了,關(guān)鍵在于new Function("obj","return "obj."+expr) 。多么巧妙啊。此之中巧,不足以言語(yǔ)道哉。
這下面就是真正的好戲了,看一看readRecords函數(shù)。
this.jsonData = o;
if(o.metaData){
delete this.ef;
this.meta = o.metaData;
this.recordType = Ext.data.Record.create(o.metaData.fields);
this.onMetaChange(this.meta, this.recordType, o);
}
定義一個(gè)jsonData屬性以保存原始json對(duì)象。然后如果傳過(guò)的json對(duì)象中就有metaData。那么,就用它自帶的meta來(lái)取代JsonReader構(gòu)造函數(shù)中所傳入的meta。以原來(lái)自帶的為主。這個(gè)功能方檔未曾提及,但我輩不可不察也。
var s = this.meta, Record = this.recordType,
f = Record.prototype.fields, fi = f.items, fl = f.length;
有人不理解了,為什么非得這樣呢?這是節(jié)省帶寬啊。如果這些東西以后多說(shuō)現(xiàn)幾次,那么每個(gè)用戶都要多下載一些東西,成千上萬(wàn)人能節(jié)省多少啊。
if (!this.ef) {
if(s.totalProperty) {
this.getTotal = this.getJsonAccessor(s.totalProperty);
}
if(s.successProperty) {
this.getSuccess = this.getJsonAccessor(s.successProperty);
}
this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
if (s.id) {
var g = this.getJsonAccessor(s.id);
this.getId = function(rec) {
var r = g(rec);
return (r === undefined || r === "") ? null : r;
};
} else {
this.getId = function(){return null;};
}
this.ef = [];
for(var i = 0; i < fl; i++){
f = fi[i];
var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
this.ef[i] = this.getJsonAccessor(map);
}
}
因?yàn)橐鶕?jù)meta.id、meta.root。這兩值都是字符串,這就要用到前面定義的getJsonAccessor函數(shù)了。這兒正是來(lái)生成幾個(gè)取json對(duì)象中屬性的函數(shù),如:getTotal、getSuccess、getRoot、getId、ef數(shù)組,一個(gè)ef數(shù)組就解決了屬性映射的問(wèn)題,真是漂亮。
var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
if(s.totalProperty){
var v = parseInt(this.getTotal(o), 10);
if(!isNaN(v)){
totalRecords = v;
}
}
if(s.successProperty){
var v = this.getSuccess(o);
if(v === false || v === 'false'){
success = false;
}
}
這兒是求totalRecords、success。有一事要注意:其中:
c = root.length, totalRecords = c
這上c后面要用來(lái)循環(huán)的,而totalRecords是要返回的,而后,又求了totalRecords,這個(gè)意思是:如果結(jié)果中沒(méi)有 totalProperty這一屬性,那么就自動(dòng)求取,如果存在,則以定義的totalProperty為主,由此可見(jiàn),totalProperty是可有可無(wú)的。這個(gè)問(wèn)題文檔不曾見(jiàn)之。諸位可無(wú)憂矣。
var records = [];
for(var i = 0; i < c; i++){
var n = root[i];
var values = {};
var id = this.getId(n);
for(var j = 0; j < fl; j++){
f = fi[j];
var v = this.ef[j](n);
values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, n);
}
var record = new Record(values, id);
record.json = n;
records[i] = record;
}
return {
success : success,
records : records,
totalRecords : totalRecords
};
這是剩余的代碼了,由for(var i = 0; i < c; i++)可知,循環(huán)的時(shí)候還是用root.length的。而不是totalProperty。這個(gè)要分清,事實(shí)上,totalProperty只是直接返回罷了,未做任何改動(dòng)。里面就轉(zhuǎn)化成Record了。其中,這個(gè)ef數(shù)組用得巧妙。類型轉(zhuǎn)化用了convert。這個(gè)東西前文已講,不足道哉。
var record = new Record(values, id);
id=this.getId(n),可見(jiàn)啦,id并非前文所說(shuō)的主鍵,它只是一個(gè)用來(lái)做客戶端唯一編號(hào)的東西,如對(duì)此有疑,可見(jiàn)于Ext.data.Record類。
record.json = n,json這個(gè)屬性我在Ext.data.Record類中并未曾得見(jiàn),諸君注意了,這個(gè)東西也許會(huì)有用。另外,readRecords返回的不只是一個(gè)records數(shù)組,而是一個(gè)json對(duì)象,包含success、records、totalRecords。
至此,JsonReader源代碼分析完畢,呵呵,因?yàn)檫@個(gè)類代碼量較少,故講得詳細(xì)。