Ext的数据源结构

要说Ext的数据源结构,确实还不知道从何说起,Ext的数据源的主体应该说是以Ext.data.Store类为主体,虽然它是主体,但其中涉及的类却比较多,要把数据源的结构弄清,对于这些相关的类也要有所了解,现在就把一些相关的类研究结果总结一下:

Ext.util.MixedCollection

这个类是一个容器类,为什么要说这个类呢?因为在数据源中很多数据都是用它包装的,所以把这个类好好研究一下是有必要,这是一个设计的非常优秀的容器,从它的命名上可以看出它是一个混合容器,它不仅同时具有索引和map的特性,而且还支持对容器的监听。这个容器类的主要成员有:

this.items = [];//值的容器

    this.map = {};//键值的映射对象

    this.keys = [];//键的容器

    this.length = 0;//容器的大小

其中由items来支持索引,由map来支持图,它实现的所有操作如下

add( String key, Object o ) : Object

添加一个元素到容器中

addAll( Object/Array objs ) : void

添加一个元素到容器中,或者添加一个数组中的所有元素到容器中

clear() : void

清除容器中所有的元素

clone() : MixedCollection

创建容器的一个拷贝

contains( Object o ) : Boolean

判断容器是否包含指定的元素

containsKey( String key ) : Boolean

判断容器是否包含指定的key

each( Function fn, [Object scope] ) : void

对每个元素调用指定的方法fn,方法第一个参数元素本身,第二个参数是元素的索引,第三个参数是容器的大小,在对每一个元素调用方法时,如果方法返回false则停止调用

eachKey( Function fn, [Object scope] ) : void

对每个元素调用指定的方法fn,方法的第一个参数为元素的key,第二个参数元素本身,第三个参数是元素的索引,第四个参数是容器的大小

filter( String property, String/RegExp value ) : MixedCollection

返回当前容器的一个子容器,过滤条件是对指定的属性的值进行正则表达式进行测试,如果返回是true则此元素将包含在子容器中,否则将会被排除在外

filterBy( Function fn, [Object scope] ) : MixedCollection

返回当前容器的一个子容器,过滤条件是对每一个元素调用方法fn,如果方法返回true则此元素将包含在子容器中,否则将会被排除在外,方法的第一个参数为元素本身,第二个参数是这个元素的key

find( Function fn, [Object scope] ) : Object

返回第一个符合条件的元素,条件是对元素调用fn方法返回true表示符合条件,方法的第一个参数是元素本身,第二个参数是此元素的key

first() : Object

返回容器的第一个元素

get( String/Number key ) : Object

返回指定的key或者索引的元素

getCount() : Number

返回容器的大小.

getKey( o {Object} ) : Object

返回指定元素的key值,这个方法可以在定义容器的时候重写,默认是返回这个元素的id属性的值

getRange( [Number startIndex], [Number endIndex] ) : Array

返回指定索引范围中的元素作为一个数组返回

indexOf( Object o ) : Number

返回对象的索引值

indexOfKey( String key ) : Number

返回key的索引值

insert( Number index, String key, [Object o] ) : Object

在指定的索引处插入一个元素

item( String/Number key ) : Object

get方法相同,返回指定key或者索引的元素.

itemAt( Number index ) : Object

返回指定索引处的元素

key( String/Number key ) : Object

返回指定key所映射的元素.

keySort( [String direction], [Function fn] ) : void

将容器中的元素按key进行排序,可以指定升降序以及比较方法

last() : Object

返回容器中的最后一个元素

remove( Object o ) : Object

删除容器中的指定的元素

removeAt( Number index ) : void

删除指定索引处的元素

removeKey( String key ) : void

删除指定key所映射的元素

replace( String key, [o {Object}] ) : Object

替换指定key的映射值,如果key不存在,则退化成添加元素

sort( [String direction], [Function fn] ) : void

对容器中的元素进行排序,可以给出对元素的比较方法

 

 Ext.data.Field

这一个类并不是一个对外公开的,也就是说在实际应用,我们并不需要使用到这个类,但是如果我们要了解数据源的内部结构,我认为还是有必要了解一下这个类。在js中我们有多种途径去获取数据,并且获取的数据的结构也各不相同,因此Ext觉得有必要建立一个公共数据访问平台或者说结构来供Ext使用,Ext采用了类似于数据库的抽象方式,将数据抽象为记录,然后将各种各样的数据结构转化为这种记录的形式,这样就可以保证使用数据的程序的相对稳定性。那么如何抽象记录呢?Ext.data.Field类就是其中的一个关键,我们说记录通常都是由字段组成,我们说在数据库中也有定义字段的说法,就是给字段命一个名字,说明它的类型,是否可以为空等一系列的属性说明,那么Ext.data.Field类与这有些类似它就是对记录的字段的一个抽象,抽象的属性与方法如下:

name:字段的名字,每个字段总要有个名字,就象数据库的字段名一样

mapping: 这个属性主要是给实现 {@link Ext.data.Reader} 读取器接口的读取器来使用的,要从一个给定的数据块中取出这个字段的值,就需要这个属性,如果没有设置这个属性的值,那么就使用name属性的值作为这个属性的值。如果一个记录对象的值是由{@link Ext.data.JsonReader}读取器来填充,那么这个属性应该设置成相对于JSON数据块中的数据成员的引用;如果记录的值是由{@link Ext.data.XmlReader} 读取器来填充,那这个属性应该设置成{@link Ext.DomQuery}路径,这个路径是相对于记录元素的。如果表达式与name属性相同,则可以省略mapping属性的设置。

type : 用于将前面读取的数据转换成这里指定的类型,可以指定的类型有:

autostringintfloatbooleandate

sortType : 排序类型,它应该被指定为{@link Ext.data.SortTypes}类的一个成员(实际是一类转换方法),这里要注意分清排序类型与数据类型是有区别的,虽然通常它们是重叠的,比如数据类型是整数,但是我想将它按字符串来排序,这个时候要分清

sortDir : 排序的升降序控制,可选择的值有"ASC" or "DESC"

convert : 如果无法通过type属性将读取器读取的数据转换需要的结果,或者对数据有特殊的需求,则可以使用此属性,它是唯一参数是获取的原始值。

dateFormat: 如果设置type属性是date,因为日期可能有多种形式,所以需要指定一个格式,格式具体说明参考:{@link Date#Date.parseDate}

Ext.data.Record

Ext.data.Record类可以说是与上面的Ext.data.Field类是紧密相联的,我们说对于数据库中的一条记录,通常都是与字段相关的,记录的字段的定义实际是对数据记录的一种抽象,因此对记录字段信息的描述通常都是作为元信息的,在Ext中的这个数据源也这样做的,它将记录字段的定义作为元信息,存放在Ext.data.Record类的prototype中因为记录可能存在多个字段域,因此在Ext.data.Record类的prototype存放了此记录类型的所有字段的定义,并将它们放在一个Ext.util.MixedCollection容器中,再将这个容器对象放在Ext.data.Record类的prototype中。这个类通常不会直接使用它的构造方法,因为它只是对记录的一个高度抽象,具体这种记录具有什么样的结构,它并不知道,因为世界上的记录结构多种多样,就像数据库的表结构没有穷尽一样,因此在定义记录时结构时通常会建立Ext.data.Record类的一个子类,在这个子类中去定义它的具体结构通常会用如下的形式(其中create静态方法就是建立它的具体的子类)

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!'

});

一般来说Ext.data.Record类或它的子类都有一个相同的构造方法:

function(data, id){

    this.id = (id || id === 0) ? id : ++Ext.data.Record.AUTO_ID;

    this.data = data;

};

注意:在数据库中通常一条记录都会有一个唯一的id,在这里也一样,第二个参数就是一个唯一的id,如果构造实体时给出,就使用给出的值作为此记录的id值,如果没有给出,则使用其默认的id值(从1001开始自增),data参数一定是按照构造方法中定义的字段结构,给出的一个数据对象。

Ext.data.Record类对外公开的方法主要有:

Record( Array data, [Object id] )

通常不会用这个构造方法,而是由create方法建立一个子类,然后调用此子类的构造方法

 
 

commit() : void

 

这个方法通常被Ext.data.Stor类来使用

 

copy( [String id] ) : Record

 

创建这个记录的一个拷贝

 

create( [Array o] ) : void

 

静态方法,建立这个类的一个子类,参数定义了子类的记录具体结构.

 

get( String name ) : Object

 

获取指定字段名的字段值

 

reject() : void

 

这个方法通常被Ext.data.Stor类来使用

 

set( String name, Object value ) : void

 

设置指定字段名的字段值

 

 

 

Ext.data.DataReader

Ext.data.DataReader类本身没有什么可关注的,因为它是一个抽象基类,主要用于设置两个重要成员,一个是元信息,另一个记录类型,构造方法如下:

Ext.data.DataReader = function(meta, recordType){

    this.meta = meta;

    this.recordType = recordType instanceof Array ?

        Ext.data.Record.create(recordType) : recordType;

};

对于一个数据读取器,它必须要有一个记录类型,因为它要为数据的读取提供信息,要不然它怎么知道去读数据块中的相关数据呢?这个记录类型实际就是Ext.data.Record类的一个子类的构造方法,最后在读取器中还需要通过这个构造方法来生成记录的实例。对于读取器主要有两个重要的方法:

read( Object response ) : Object

这个方法一般会被一个DataProxy类的实例调用,并且这个DataProxy已经从远程服务器上获取了相应的数据

readRecords( Object o ) : Object

创建一个包含Ext.data.Record实例对象.

实际上上面两个方法返回的对象大体上如下:

{

     success : success,

     records : records,

     totalRecords : totalRecords || records.length

}

其中records成员就是读取的记录数据,success是远程返回的成功与否的状态,totalRecords:可能是从远程服务器上传过来的总记录数或者也可能是实际读取的记录数据,到这里可以看一下元信息,前面提到在构造读取器的时候,可以传递一些元信息,那它们究竟是什么呢?元信息结构可能大体如下:

{

totalProperty: "results",

    root: "rows"

    id: "id"

}

这里元信息与在Field类中的定义有相同的效果:{name:”totalProperty”, mapping:”results”}它主要告诉读取器要获取左边的属性值,需要在原始数据块中通过什么映射值去获取。此类主要有三个实现类:Ext.data.JsonReaderExt.data.XmlReaderExt.data.ArrayReader

  

Ext.data.DataProxy

它是一个数据代理的抽象基类,它本身只对几个事件提供支持,那么究竟什么是一个数据代理呢?从抽象层次上看,它实际是对一个读取器的一个更高层次的包装,如果读取器是一个类型公共的抽象平台或者说是转换器,那数据代理可以看成是一个数据提供者,它就是对上层应用提供相同结构的数据。在前面看读取器时可以看到读取器只是把原始数据转换成公共平台数据结构,但是原始数据从哪里来呢?数据代理主要的一个工作就是从本地或者远程获取原始数据,然后委托读取器将原始数据转换成公共平台数据。数据代理对外公开的接口只有一个:

load( Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg ) : void

加载数据,此方法并不返回转换后的数据,要处理数据,必须通过回调来处理,回调方法的参数:第一个参数为转换后的数据结果,第二个参数为从load方法传入的参数,第二个参数为加载是否成功的状态

在加载数据的时候,会在适当的时候触发beforeloadloadloadexception事件,因此为了处理数据,除了可以通过回调方法来处理,也可以通过数据代理的监听器来处理数据。数据代理主要有三个实现类:Ext.data.MemoryProxyExt.data.HttpProxyExt.data.ScriptTagProxy

 

Ext.data.Store

Ext.data.Store类是Ext中对数据源最高抽象,它对前面所提到的读取器以及数据代理进行了封装,它主完成两个方面的工作:一就是对数据进行加载(在适当的时候触发加载相关的事件),二就是对数据进行CRUD操作(在适当的时候会触发CRUD方面的事件)。对数据的加载主要是委托数据代理去完成的,而CRUD是委托混合容器Ext.util.MixedCollection去完成的。因此对于这个类主要要研究一下它的加载和CRUD方面的配置。在构造Ext.data.Store类实例时的配置项如下:

baseParams : Object

基础参数对象,可能象这样的形式{param:”value”…}

data : Array

初始化时需要加载的原始数据块,这个数据块我想一定要符合record数据结构的定义

proxy : Ext.data.DataProxy

数据代理.

pruneModifiedRecords : boolean

如果设为true,则当store每次被加载或当一条记录被删除时,所有的修改记录信息将会被删除。

reader : Ext.data.Reader

读取器

remoteSort : Boolean

如果设置为true将会进行远程的排序,否则将会在本地进行排序

sortInfo : Object

排序信息格式:{field: "fieldName", direction: "ASC|DESC"}

上面是在构造Ext.data.Store类实例时的配置项,另外在加载数据方法load调用时也会指定一系列的配置项,这些配置项对于控制数据数据的加载也是很重的,关于它们的说明如下:

·         params {Object} 要传传递的Http参数.

·         callback {Function}加载后的回调方法,回调方法的参数:

o        r : Ext.data.Record[]

o        options: load方法传递过来的选项参数

o        success: 加载成功与否的状态

·         scope {Object} Scope 名空间

·         add {Boolean} 确定加载数据时是使用追加还替换方式

Ext.data.Store类对外公开的接口如下:

add( Ext.data.Record[] records ) : void

添加记录.

clearFilter( Boolean suppressEvent ) : void

Revert to a view of the Record cache with no filtering applied.

collect( String dataIndex, [Boolean allowNull], [Boolean bypassFilter] ) : Array

Collects unique values for a particular dataIndex from this store.

commitChanges() : void

提交所有的修改

each( Function fn, [Object scope] ) : void

fn回调迭代每一元素,如果返回false则停止迭代.

filter( String field, String/RegExp value, Boolean anyMatch ) : void

通过字段及模式配置获取记录集

filterBy( Function fn, [Object scope] ) : void

通过回调访求过滤记录集

getAt( Number index ) : Ext.data.Record

通过索引获取记录.

getById( String id ) : Ext.data.Record

通过id获取记录.

getCount() : void

获取缓存记录的总数

getModifiedRecords() : Ext.data.Record[]

获取自最后一次加载或最后一次提交后所有修改过的记录的集合.

getRange( [Number startIndex], [Number endIndex] ) : Ext.data.Record[]

获取一个范围内的记录.

getSortState() : Object

获取排序状态

getTotalCount() : void

获取记录的总数

indexOf( Ext.data.Record record ) : Number

给出记录查找其索引

indexOfId( String id ) : Number

给出id查找其索引.

insert( Number index, Ext.data.Record[] records ) : void

插入一批记录.

load( Object options ) : void

根据配置加载数据

loadData( Object data, [Boolean append] ) : void

手动加载一个指定的数据块

query( String field, String/RegExp value, Boolean anyMatch ) : MixedCollection

指定字段与配置模式查找记录

queryBy( Function fn, [Object scope] ) : MixedCollection

通过回调查找子容器(实际调用filterBy)

rejectChanges() : void

仍掉所有记录的变更信息.

reload( [Object options] ) : void

重新加载数据,加载选项是当前指定与最后一次配置的综合

remove( Ext.data.Record record ) : void

删除指定的记录.

removeAll() : void

删除所有记录.

setDefaultSort( String fieldName, [String dir] ) : void

设置默认的排序配置

sort( String fieldName, [String dir] ) : void

排序,如果设置了远程排序,则会从服务加载数据,否则直接在本地排序

sum( String property, Number start, Number end ) : Number

Sums the value of property for each record between start and end and returns the result.

 

通过上面的分析可以总结如:

Ext.data.Field相当于字段抽象,它的实例就是一个具体的字段,至于是什么字段要看具体定义;Ext.data.Record相当于表定义,至于是什么要看其子类对它的覆盖情况,它的一个实例就是一条记录,每一条记录都对应着相同的字段定义,它们被这些定义被放在Ext.data.Recordprototype中。一般不定义字段的实例,它们是在定义一个具体的Ext.data.Record时,也就是在定义它的一个具体的子类时被放入到这个子类的prototype中的,没有必须单独来定义一个具体的字段的实例。事实Ext.data.Record的子类也很少定义,通常这个子类都是由一个实现Ext.data.DataReader接口的类来创建这个子类

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值