Extjs学习笔记之九 数据模型(上)


Posted in Javascript onJanuary 11, 2010

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的官方文档这里相当含糊不清:
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。然后我们创建一个表单:

Extjs学习笔记之九 数据模型(上)

添加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按钮,结果出来了:

Extjs学习笔记之九 数据模型(上)

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

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

太长了…转下篇…

Javascript 相关文章推荐
IE8 浏览器Cookie的处理
Jan 31 Javascript
dwr spring的集成实现代码
Mar 22 Javascript
Extjs4 消息框去掉关闭按钮(类似Ext.Msg.alert)
Apr 02 Javascript
JavaScript包装对象使用介绍
Aug 29 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
May 23 Javascript
JavaScript通过this变量快速找出用户选中radio按钮的方法
Mar 23 Javascript
限制复选框最多选择项的实现代码
May 30 Javascript
一个极为简单的requirejs实现方法
Oct 20 Javascript
layui文件上传实现代码
May 20 Javascript
vue脚手架中配置Sass的方法
Jan 04 Javascript
vuejs使用axios异步访问时用get和post的实例讲解
Aug 09 Javascript
vue封装自定义指令之动态显示title操作(溢出显示,不溢出不显示)
Nov 12 Javascript
JavaScript 事件冒泡简介及应用
Jan 11 #Javascript
Javascript 读书笔记索引贴
Jan 11 #Javascript
Javascript学习笔记9 prototype封装继承
Jan 11 #Javascript
Javascript学习笔记8 用JSON做原型
Jan 11 #Javascript
Javascript学习笔记7 原型链的原理
Jan 11 #Javascript
Javascript学习笔记6 prototype的提出
Jan 11 #Javascript
Javascript学习笔记5 类和对象
Jan 11 #Javascript
You might like
PHP中=赋值操作符对不同数据类型的不同行为
2011/01/02 PHP
php无限遍历目录示例
2014/02/21 PHP
PHP实现获取FLV文件的时间
2015/02/10 PHP
如何优雅的使用 laravel 的 validator验证方法
2018/11/11 PHP
Laravel实现批量更新多条数据
2020/04/06 PHP
firefox中用javascript实现鼠标位置的定位
2007/06/17 Javascript
JQuery 学习笔记 选择器之三
2009/07/23 Javascript
innerHTML与jquery里的html()区别介绍
2012/10/12 Javascript
jquery的相对父元素和相对文档定位示例代码
2013/08/02 Javascript
Extjs改变树节点的勾选状态点击按钮将复选框去掉
2013/11/14 Javascript
JavaScript Array对象详解
2016/03/01 Javascript
详解微信小程序开发之下拉刷新 上拉加载
2016/11/24 Javascript
react.js 翻页插件实例代码
2017/01/19 Javascript
基于JavaScript实现轮播图原理及示例
2020/04/10 Javascript
JS获得一个对象的所有属性和方法实例
2017/02/21 Javascript
原生javascript移动端滑动banner效果
2017/03/10 Javascript
详解JavaScript数组过滤相同元素的5种方法
2017/05/23 Javascript
详解Nodejs之npm&amp;package.json
2017/06/15 NodeJs
js实现倒计时秒杀效果
2020/03/25 Javascript
JS实现横向轮播图(中级版)
2020/01/18 Javascript
微信小程序连续签到7天积分获得功能的示例代码
2020/08/20 Javascript
python 正则式 概述及常用字符
2009/05/07 Python
基于Python闭包及其作用域详解
2017/08/28 Python
Python 找到列表中满足某些条件的元素方法
2018/06/26 Python
手把手教你如何安装Pycharm(详细图文教程)
2018/11/28 Python
Python操作Excel插入删除行的方法
2018/12/10 Python
详解Python 中sys.stdin.readline()的用法
2019/09/12 Python
Python进程池Pool应用实例分析
2019/11/27 Python
Python turtle画图库&amp;&amp;画姓名实例
2020/01/19 Python
Django CBV模型源码运行流程详解
2020/08/17 Python
香港礼品网站:GiftU eshop
2017/09/01 全球购物
时尚孕妇装:HATCH Collection
2019/09/24 全球购物
机电一体化职业规划书
2014/01/07 职场文书
儿媳婚宴答谢词
2014/01/14 职场文书
教师通用专业自荐书范文
2014/02/11 职场文书
副主任竞聘演讲稿
2014/08/18 职场文书