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 相关文章推荐
用JavaScript调用WebService的示例
Apr 07 Javascript
用apply让javascript函数仅执行一次的代码
Jun 27 Javascript
Js 时间函数getYear()的使用问题探讨
Apr 01 Javascript
javascript获取四位数字或者字母的随机数
Jan 09 Javascript
使用jquery清空、复位整个输入域
Apr 02 Javascript
js中flexible.js实现淘宝弹性布局方案
Jun 23 Javascript
JS集成fckeditor及判断内容是否为空的方法
May 27 Javascript
使用 Vue.js 仿百度搜索框的实例代码
May 09 Javascript
详谈js对url进行编码和解码(三种方式的区别)
Aug 16 Javascript
JS设计模式之访问者模式定义与用法分析
Feb 05 Javascript
js 对象使用的小技巧实例分析
Nov 08 Javascript
vue el-table实现递归嵌套的示例代码
Aug 14 Vue.js
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
缅甸的咖啡简史
2021/03/04 咖啡文化
php带密码功能并下载远程文件保存本地指定目录 修改加强版
2010/05/16 PHP
PHP中开发XML应用程序之基础篇 添加节点 删除节点 查询节点 查询节
2010/07/09 PHP
php中OR与|| AND与&amp;&amp;的区别总结
2013/10/26 PHP
基于CakePHP实现的简单博客系统实例
2015/06/28 PHP
四个常见html网页乱码问题及解决办法
2015/09/08 PHP
thinkphp跨库操作的简单代码实例
2016/09/22 PHP
Yii 2中的load()和save()示例详解
2017/08/03 PHP
php求斐波那契数的两种实现方式【递归与递推】
2019/09/09 PHP
用jscript实现新建和保存一个word文档
2007/06/15 Javascript
js 调用父窗口的具体实现代码
2013/07/15 Javascript
解决Jquery鼠标经过不停滑动的问题
2014/03/03 Javascript
select多选 multiple的使用示例
2014/06/16 Javascript
jquery实现的淡入淡出下拉菜单效果
2015/08/25 Javascript
详解Javascript中的Object对象
2016/02/28 Javascript
AngularJS框架中的双向数据绑定机制详解【减少需要重复的开发代码量】
2017/01/19 Javascript
jQuery插件HighCharts绘制简单2D柱状图效果示例【附demo源码】
2017/03/21 jQuery
JS简单实现数组去重的方法示例
2017/03/27 Javascript
vue-router实现tab标签页(单页面)详解
2017/10/17 Javascript
security.js实现的RSA加密功能示例
2018/06/06 Javascript
vue-cli3.0 环境变量与模式配置方法
2018/11/08 Javascript
Angular6使用forRoot() 注册单一实例服务问题
2019/08/27 Javascript
js获取本日、本周、本月的时间代码
2020/02/01 Javascript
深入了解Vue动态组件和异步组件
2021/01/26 Vue.js
[02:28]DOTA2 2015国际邀请赛中国区预选赛首日现场百态
2015/05/26 DOTA
Python中exit、return、sys.exit()等使用实例和区别
2015/05/28 Python
Python数据分析之真实IP请求Pandas详解
2016/11/18 Python
python实现简单中文词频统计示例
2017/11/08 Python
对Python中list的倒序索引和切片实例讲解
2018/11/15 Python
Ubuntu16安装Python3.9的实现步骤
2020/12/15 Python
HTML5调用手机发短信和打电话功能
2020/04/29 HTML / CSS
销售自我评价
2013/10/22 职场文书
班风学风建设方案
2014/05/06 职场文书
工作求职信
2014/07/04 职场文书
SQLServer2008提示评估期已过解决方案
2021/04/12 SQL Server
MySQL触发器的使用
2021/05/24 MySQL