Store类提供对记录集(Record)的包装,通过前面的研究可知,DataProxy取数据(url或数组或xml或json),DataReader用于从不规范的数据取出并格式化指定结构的记录集。记录的结构由Record.create创建。
DataProxy通过对Connection的调用取得数据(Response)后,在回调中调用DataReader的read函数,从而把response中的数据解析成记录集,这个记录集将再以回调参数的形式传出来,store实现这个回调,并把里面的Recodrd[]取出来,放到data这个成员中。store.data是一个MixedCollection对象,MixedCollection作什么用的前面也讲过,它本质就是一个容器,ExtJs确实很好,连容器类都写了。
有了store.data,数据进了这儿,就好办了,store调用MixedCollection的功能,实现了一些通用的函数,如取指定成员、查询、遍历、事务等等,这些都不足道。什么提交修改、取消修改的功能却是根源于Record。Record类自身就封装了这个功能,Store中只是再次封装罢了,这个原理也很简单。看代码即知。
上面讲的是通用原理,是大概,下面拣紧要的代码说一下。
它定义了构造函数,继承自Ext.Observable。第一行代码就是个重点:
this.data = new Ext.util.MixedCollection(false);
这是定义data,所有记录都将保存在它里面。
this.baseParams = {};
// private
this.paramNames = {
"start" : "start",
"limit" : "limit",
"sort" : "sort",
"dir" : "dir"
};
baseParams将在调用HttpProxy时用到,它将作为params附加到url末尾。这个东西没有悬念。至于paramsNames用于保存参数名,start、limit应当用于分页,sort、dir用于排序,不过,我看了通篇的代码,发现,Store本身不提供任何其他分页、排序功能的实现,还是得依靠服务器端的。只不过,这儿提供一种统一的方式罢了。
if(config && config.data){
this.inlineData = config.data;
delete config.data;
}
意思是说,如果创建store时,设了config,且config.data存在,那么,将直接从config.data中loadData。构造函数后面一点就有。inlineData这个属性没活多久就被delete了。
if(this.url && !this.proxy){
this.proxy = new Ext.data.HttpProxy({url: this.url});
}
if(this.reader){ // reader passed
if(!this.recordType){
this.recordType = this.reader.recordType;
}
if(this.reader.onMetaChange){
this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
}
}
if(this.recordType){
this.fields = this.recordType.prototype.fields;
}
就是根据config中的情况,创建成员:proxy,reader,recordType,onMetaChange。这了这四个,就好方便在下面定义的load中加载数据并完全记录集的封装。说出来一文不值。
this.modified = [];
这个东西用于保存那些有修改过的记录的旧值。之所以能取消修改,正是源于此啊。
关于addEvents那个语句,就没必要讲了,大伙都懂。
if(this.proxy){
this.relayEvents(this.proxy, ["loadexception"]);
}
this.sortToggle = {};
if(this.sortInfo){
this.setDefaultSort(this.sortInfo.field, this.sortInfo.direction);
}
Ext.data.Store.superclass.constructor.call(this);
if(this.storeId || this.id){
Ext.StoreMgr.register(this);
}
if(this.inlineData){
this.loadData(this.inlineData);
delete this.inlineData;
}else if(this.autoLoad){
this.load.defer(10, this, [
typeof this.autoLoad == 'object' ?
this.autoLoad : undefined]);
}
第一个语句中主要就是一个relayEvents,意为延迟事件,这个延迟不是时间延迟哦。它是将当前对像的某些事件处理函数作为另一个对象的处理函数,同者共享,事实上,它的作用就是利用另一对象的事件来触发本对象的事件,从而引发事件处理函数的执行(说得太拗口了吧)。
那个inlineData上面讲了的,现在应验了,不多讲。从这儿可以看出,如果已从config中传过来数据,那么以直接传的数据为准,如果没有直接传数据,而是通过url,且autoLoad为true,这时就在构造函数中加载数据且完全数据的封装。
重点代码至此讲了一半,另一半就是load、loadRecords了。