来源:niutuku.com | vincent上传于2012-07-20 | 1802次浏览 | 0条评论

本文开始进入Extjs最核心最优秀的部分。

标签:Extjs 数据模型

 
Extjs的数据模型分为以下几个部分:

数据记录 Record 
数据集合中的一个条记录,包括数据的定义和值。相当于实体类。 
数据代理 Proxy 
用来获取数据的代理。相当于Datasource。 
数据解析器 DataReader 
负责将Proxy获取的数据解析出来传换成Record并存入Store中。相当于C#的DataReader。 
数据集 Store 
一个保存数据的集合,类似于C#的Datatable。 
Extjs3的Proxy较以前版本有了一些变动,资料很少,而且官方文档上相当简练,以至于一个完整的例子都没有…… 我尽力理解……

1. 数据记录 
一条数据记录一般是有多个字段组成的。字段由Ext.data.Field类定义。Field的配置项很丰富,使我们有足够的信息在弱类型的语言中处理我们的数据,主要有:

name:字段名;defaultValue:默认值;type:数据类型,可以是string,int,float,boolean,date和auto(默认)。先介绍这么多,其余的在具体用到的时候再介绍。

要建立一个数据记录类(注意不是具体一条数据),可以使用Ext.data.Record.create方法,这个方法接受一个数组的Field类的配置项,返回一个构造函数。看一个例子:

复制代码代码如下:
<script type="text/javascript"> 
// create a Record constructor from a description of the fields 
var TopicRecord = Ext.data.Record.create([ // creates a subclass of Ext.data.Record 
{name: 'title' }, 
{ name: 'author', allowBlank: false }, 
{ name: 'totalPosts', type: 'int' }, 
{ name: 'lastPost',type: 'date' }, 
// In the simplest case, if no properties other than name are required, 
// a field definition may consist of just a String for the field name. 
'signature' 
]);

// create Record instance 
var myNewRecord = new TopicRecord( 

title: 'Do my job please', 
author: 'noobie', 
totalPosts: 1, 
lastPost: new Date(), 
signature: '' 
}, 
id // optionally specify the id of the record otherwise one is auto-assigned 
); 
alert(myNewRecord.get('author')); 
</script> 

这里演示的仅仅是Record最基本的功能:定义字段和存取数据。Record还可以和Store一起,由Store跟踪Record的变化情况。就如C#的DataTable一样,可以跟踪其内部的DataRow变更的情况。Extjs几乎把前台开发变成了后台。这些内容等介绍Store的时候再介绍。

2.数据代理 
Ext.data.DataProxy是数据代理的抽象基类,实现了DataProxy的通用公共接口。DataProxy的最重要的通用方法就是doRequest,执行这个方法之后将从各种具体的数据源读取数据。继承自DataProxy的具体Proxy类有:

2.1 HttpProxy

这是最常用的proxy,通过一个http请求从远程服务器获取数据。HttpProxy最重要的配置项就是配置获取数据的url。HttpProxy不仅仅支持获取数据,它支持对数据的CRUD操作。DataProxy的api属性就是用来配置这4种操作对应的url的。如果不配置,就采用HttpProxy的url属性。例如:

复制代码代码如下:
api: { 
read: '/controller/load', 
create : '/controller/new', // Server MUST return idProperty of new record

save : '/controller/update', 
destroy : '/controller/destroy_action' 

注意,extjs的官方文档这里相当含糊不清: 

四个操作中的第一个到底是read还是load??? 
配置好api后,就可以执行doRequest方法,doRequest方法的参数比较复杂:

doRequest( String action, Ext.data.Record/Ext.data.Record[] rs, Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg )含义如下:action:表示执行的是哪种操作,可以是 create,read,update,destroy的一种。rs: 看了半天也没发现这个参数有什么用…… 看源代码发现其中出现了这样的表达式 url+rs.id,这个或许是为MVC架构的程序更好的构建url用的?直接忽略它,设为null即可。params:这个对象里边的属性:值对会作为post/get的参数传到服务器,非常有用。

reader: DataReader,将服务器返回的数据解析成Record的数组。下面会有更详细的解释。

callback:当读取到服务器数据之后执行的函数。这个函数接受三个参数,分别是: r Ext.Record[],服务器端返回的经过reader的数组。这是官方的说法,实际测试下来似乎只有当action是read的时候才是这样,下面有介绍;options:就是arg参数的值。success:是否成功的标致,bool,这个也是服务器端返回的。

scope:作用域

arg:一些附加的参数,会被传到callback的options参数中。

下面我们来完成一个例子,利用httpproxy完成基本的CRUD操作。先看服务器端代码:

复制代码代码如下:
<%@ WebHandler Language="C#" class="dataproxy" %>

using System; 
using System.Web; 
using System.Collections.Generic;

public class dataproxy : IHttpHandler { 
static List<Student> db = new List<Student>(); 
static dataproxy() 

db.Add(new Student { Id = "1", Name = "Li", Telephone = "1232" }); 
db.Add(new Student { Id = "2", Name = "Wang", Telephone = "5568" }); 
db.Add(new Student { Id = "3", Name = "Chen", Telephone = "23516" }); 
db.Add(new Student { Id = "4", Name = "Zhu", Telephone = "45134" }); 
db.Add(new Student { Id = "5", Name = "Zhou", Telephone = "3455" }); 

public void ProcessRequest (HttpContext context) { 
string id = context.Request.Params["id"]; 
string action=context.Request.Params["action"]; 
string result = "{success:false}"; 
if (action == "create") 


else if (action == "read") 

foreach (Student stu in db) 

if (stu.Id == id) 

result = "{success:true,r:[['" + stu.Id + "','" + stu.Name + "','" + stu.Telephone + "']]}"; 
break; 



else if (action == "update") 


else if (action == "delete") 


context.Response.ContentType = "text/plain"; 
context.Response.Write(result); 
}

public bool IsReusable { 
get { 
return false; 

}

class Student 

string id; 
public string Id 

get { return id; } 
set { id = value; } 

string name; 
public string Name 

get { return name; } 
set { name = value; } 

string telephone;

public string Telephone 

get { return telephone; } 
set { telephone = value; } 


我们用一个静态的List来模仿数据库。在处理函数中分别应对4种情况。上面仅实现了read的代码,返回一个数组,因为我们最终客户端采用ArrayReader来解析数据。服务器端的代码没什么好解释的,很简单,再看客户端的:

复制代码代码如下:
<head> 
<title>Data Proxy</title> 
<link rel="Stylesheet" type="text/css" href="ext-3.1.0/resources/css/ext-all.css" /> 
<script type="text/javascript" src="ext-3.1.0/adapter/ext/ext-base-debug.js"></script> 
<script type="text/javascript" src="ext-3.1.0/ext-all-debug.js"></script> 
<script type="text/javascript" src="ext-3.1.0/src/locale/ext-lang-zh_CN.js"></script> 
<script type="text/javascript"> 
var Student = Ext.data.Record.create(['id', 'Name', 'Telephone']); 
var arrayReader = new Ext.data.ArrayReader({ 
root: 'r', idIndex: 0, fields: Student }); 
var httpProxy = new Ext.data.HttpProxy({ 
url: 'dataproxy.ashx', 
api: { 
read: 'dataproxy.ashx?action=read', 
create: 'dataproxy.ashx?action=create', 
update: 'dataproxy.ashx?action=update', 
destroy: 'dataproxy.ashx?action=delete' 

}); 
Ext.onReady(function() { 
var form = new Ext.FormPanel({ 
renderTo: document.body, 
height: 160, 
width: 400, 
frame: true, 
labelSeparator: ':', 
labelWidth: 60, 
labelAlign: 'right', 
defaultType: 'textfield', 
items: [ 
{ fieldLabel: 'ID', 
id: 'ID' 
}, 
{ fieldLabel: 'Name', 
id: 'Name' 
}, 
{ fieldLabel: 'Telephone', 
id: 'Telephone' 

], 
buttons: [{ text: 'Read', handler: function() { 
httpProxy.doRequest('read', null, { id: form.getForm().findField('ID').getValue() }, arrayReader, 
function(r, option, success) { 
if (option.arrayData.success) { 
var res = r.records[0]; 
Ext.Msg.alert('Result From Server', res.get('id') + ' ' + res.get('Name') 
+' '+ res.get('Telephone')); 

else { 
Ext.Msg.alert('Result','Did not find.'); 
}

},this,arrayReader); 

}, 
{ text: 'Delete' }, { text: 'Update' }, { text: 'Create'}] 
}) 
}); 
</script> 
</head> 

这里有些东西要解释下,首先是定义了一个Student的Record,这个和服务器端的代码是一致的。然后定义了ArrayReader,ArrayReader是读取数组内的数据,数据格式参考服务器端的代码,它有一个root属性非常重要,指定的是读取json数据中哪个属性的值(这个值是一个数组的字面量).idIndex也是必须指定的,它标志着哪个字段是主键。fields就好理解了,读取的Record的字段。数组里边的顺序要和Record的字段顺序对应,否则可以通过Record的mapping属性来指定,例如: {name:'Telephone',mapping:4}就表示读取数组中第4个数值放到Telephone字段中。 下面就是定义httpProxy,设置好api。然后我们创建一个表单:

添加4个按钮。先为Read按钮写上处理函数:doRequest的一个参数是'read',第二个参数是null,因为我不懂它有什么用;第三个参数把要查询的ID的值传给服务器,第四个参数是一个reader,第五个参数callback很重要,我们在这里处理服务器的返回值。注意,我在最后一个参数设置为arrayReader,于是这个函数的option参数的值实际上就是arrayReader。我为什么要这样做呢,一来是做个演示,最后一个参数有什么用,二来是因为ArrayReader比较古怪,注意它没有公开的successProperty配置项,也就是说它无法判断服务器返回的success属性,也就是这个callback的success参数永远是undefined!我一开始以为是我服务器端的代码不对,后来debug进源代码,发现它确实不处理这个success属性。或许ArrayReader设计的本意就不是用在这个环境里的。不过作为演示,那就这样用吧。其实它不处理success参数我们自己还是可以处理的。arrayReader内部有个arrayData属性,它是一个解析好的json对象,如果返回的json字符串中有success属性那么这个对象也有success属性,这样我们就可以获得服务器的返回值,同理,也可以处理服务器返回的任何数据。当然,这种用法是文档上没有的,仅供演示。这个callback的第一个参数,要特别注意,文档上说是Record[],不过实际上它是一个对象,它的record属性才是Record[]。我只能说extjs这部分的文档很糟糕。幸好这部分的代码是很不错的,有兴趣的朋友可以调试进去看看,以便有更深刻的理解。好了,万事俱备,点击下Read按钮,结果出来了:

此文暂告一段落,其他几个操作原理上类似的,突然发现,如果单纯的用这个例子来演示似乎不太合适。因为Delete和Update服务器端都不需要返回什么数据,而doRequest强制要求用一个DataReader来解析返回的数据,很不方便。或许在操作表格型的数据的时候doRequest的其他方法才有用武之地。针对单个对象的CRUD,可以直接采用更底层的Ext.ajax方法(另文介绍),或者利用表单的方法来处理。

本文只是对Extjs的数据模型的功能和原理做一简单的介绍,在实际中如何高效的组织代码和在服务器与客户端间传递数据是一个另外的话题。Extjs还是很灵活的,客户端和服务器端的通信契约还是可以让程序员自己决定。

Extjs学习笔记之九 数据模型(上)-extjs的更多相关文章

  1. Extjs学习笔记--(一vs增加extjs智能感知)

    1,编写class.js var classList=[ "Ext.layout.container.Absolute", "Ext.layout.container.A ...

  2. VSTO学习笔记(九)浅谈Excel内容比较

    原文:VSTO学习笔记(九)浅谈Excel内容比较 说起文件内容比较,或许我们首先想到的是UltraCompare这类专业比较的软件,其功能非常强大,能够对基于文本的文件内容作出快速.准确的比较,有详 ...

  3. Directx11学习笔记【九】 3D渲染管线

    原文:Directx11学习笔记[九] 3D渲染管线 原文地址:http://blog.csdn.net/bonchoix/article/details/8298116 3D图形学研究的基本内容,即 ...

  4. 简单的玩玩etimer <contiki学习笔记之九 补充>

    这幅图片是对前面  <<contiki学习笔记之九>>  的一个补充说明. 简单的玩玩etimer <contiki学习笔记之九> 或许,自己正在掀开contiki ...

  5. c++学习笔记之封装篇(上)

    title: c++学习笔记之封装篇(上) date: 2017-03-12 18:59:01 tags: [c++,c,封装,类] categories: [学习,程序员,c/c++] --- 一. ...

  6. Python学习笔记(九)

    Python学习笔记(九): 装饰器(函数) 内置函数 1. 装饰器 1. 作用域 2. 高阶函数 3. 闭包 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就 ...

  7. python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法

    python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...

  8. 汇编入门学习笔记 (九)—— call和ret

    疯狂的暑假学习之  汇编入门学习笔记 (九)--  call和ret 參考: <汇编语言> 王爽 第10章 call和ret都是转移指令. 1. ret和retf ret指令:用栈中的数据 ...

  9. Spark学习笔记2——RDD(上)

    目录 Spark学习笔记2--RDD(上) RDD是什么? 例子 创建 RDD 并行化方式 读取外部数据集方式 RDD 操作 转化操作 行动操作 惰性求值 Spark学习笔记2--RDD(上) 笔记摘 ...

随机推荐

  1. php实现分页

    php函数 <?php////////////////////$result :容器的id//$url:请求的url//$total:总条数//$num:页容量//$pagenum:总页数//$ ...

  2. Javascript隔离方法

    1.常用的隔离方法: (function() { })(); 2.query的隔离方法: 需要引入jquery: <script type="text/javascript" ...

  3. 原生js的各种方法

    原生js操作dom元素 var link = document.createElement( "link" );link.type = "image/x-icon&quo ...

  4. BufferedReader 输出与BufferedWriter 输入的用法

    public static void main(String[] args) {  String content[] = {"好久不见了","最近好吗",&qu ...

  5. MapReduce 简单的全文搜索2

    上一个全文搜索实现了模糊查找,这个主要实现了精确查找,就是比如你查找mapreduce is simple那么他就只查找有这个句子的文章,而不是查找有这三个单词的文章. 这个版本需要重写反向索引,因为 ...

  6. STM32的时钟树深入详解以及RCC配置

    在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法 如果使用内部RC振荡器而不使用外部晶振,请按照下面方法处理: 1)对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT ...

  7. 微信小程序-未接入app.json错误

    微信小程序建立新项目之后会出现app.json文件未接入错误如下图: 一般是因为在下图添加新项目,项目目录这一列,如果不事先建立一个空的文件夹,直接选择则不会出现quickstartup界面 所以在建 ...

  8. Unity3D ——强大的跨平台3D游戏开发工具(三)

    第四章 为地形添加水源.水流以及水下的模糊效果 制作好了地形的各种效果,接下来我们给场景添加一些水效果,使场景更加丰富. 第一步:添加水面 由于我在上一次的地形创作中就已经在山峰之间制作了一块洼地,它 ...

  9. 在Eclipse中配置tomcat

    为了在Eclipse中进行struts2的测试,才发现自己机器上的Eclipse没有集成Tomcat,在网上找了半天,不是这个插件没有下载地址,就是那个有好多注意事项或者版本问题. 结果,自己到tom ...

  10. Max Sum of Rectangle No Larger Than K

    Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix s ...