欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Extjs學(xué)習(xí)筆記之九 數(shù)據(jù)模型(上)

 更新時(shí)間:2010年01月11日 20:58:36   作者:  
本文開始進(jìn)入Extjs最核心最優(yōu)秀的部分。
Extjs的數(shù)據(jù)模型分為以下幾個(gè)部分:

數(shù)據(jù)記錄 Record
數(shù)據(jù)集合中的一個(gè)條記錄,包括數(shù)據(jù)的定義和值。相當(dāng)于實(shí)體類。
數(shù)據(jù)代理 Proxy
用來獲取數(shù)據(jù)的代理。相當(dāng)于Datasource。
數(shù)據(jù)解析器 DataReader
負(fù)責(zé)將Proxy獲取的數(shù)據(jù)解析出來傳換成Record并存入Store中。相當(dāng)于C#的DataReader。
數(shù)據(jù)集 Store
一個(gè)保存數(shù)據(jù)的集合,類似于C#的Datatable。
Extjs3的Proxy較以前版本有了一些變動(dòng),資料很少,而且官方文檔上相當(dāng)簡(jiǎn)練,以至于一個(gè)完整的例子都沒有…… 我盡力理解……

1. 數(shù)據(jù)記錄
一條數(shù)據(jù)記錄一般是有多個(gè)字段組成的。字段由Ext.data.Field類定義。Field的配置項(xiàng)很豐富,使我們有足夠的信息在弱類型的語言中處理我們的數(shù)據(jù),主要有:

name:字段名;defaultValue:默認(rèn)值;type:數(shù)據(jù)類型,可以是string,int,float,boolean,date和auto(默認(rèn))。先介紹這么多,其余的在具體用到的時(shí)候再介紹。

要建立一個(gè)數(shù)據(jù)記錄類(注意不是具體一條數(shù)據(jù)),可以使用Ext.data.Record.create方法,這個(gè)方法接受一個(gè)數(shù)組的Field類的配置項(xiàng),返回一個(gè)構(gòu)造函數(shù)。看一個(gè)例子:
復(fù)制代碼 代碼如下:

<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最基本的功能:定義字段和存取數(shù)據(jù)。Record還可以和Store一起,由Store跟蹤Record的變化情況。就如C#的DataTable一樣,可以跟蹤其內(nèi)部的DataRow變更的情況。Extjs幾乎把前臺(tái)開發(fā)變成了后臺(tái)。這些內(nèi)容等介紹Store的時(shí)候再介紹。

2.數(shù)據(jù)代理
Ext.data.DataProxy是數(shù)據(jù)代理的抽象基類,實(shí)現(xiàn)了DataProxy的通用公共接口。DataProxy的最重要的通用方法就是doRequest,執(zhí)行這個(gè)方法之后將從各種具體的數(shù)據(jù)源讀取數(shù)據(jù)。繼承自DataProxy的具體Proxy類有:

2.1 HttpProxy

這是最常用的proxy,通過一個(gè)http請(qǐng)求從遠(yuǎn)程服務(wù)器獲取數(shù)據(jù)。HttpProxy最重要的配置項(xiàng)就是配置獲取數(shù)據(jù)的url。HttpProxy不僅僅支持獲取數(shù)據(jù),它支持對(duì)數(shù)據(jù)的CRUD操作。DataProxy的api屬性就是用來配置這4種操作對(duì)應(yīng)的url的。如果不配置,就采用HttpProxy的url屬性。例如:
復(fù)制代碼 代碼如下:

api: {
read: '/controller/load',
create : '/controller/new', // Server MUST return idProperty of new record

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

注意,extjs的官方文檔這里相當(dāng)含糊不清:

四個(gè)操作中的第一個(gè)到底是read還是load???
配置好api后,就可以執(zhí)行doRequest方法,doRequest方法的參數(shù)比較復(fù)雜:

doRequest( String action, Ext.data.Record/Ext.data.Record[] rs, Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg )含義如下:action:表示執(zhí)行的是哪種操作,可以是 create,read,update,destroy的一種。rs: 看了半天也沒發(fā)現(xiàn)這個(gè)參數(shù)有什么用…… 看源代碼發(fā)現(xiàn)其中出現(xiàn)了這樣的表達(dá)式 url+rs.id,這個(gè)或許是為MVC架構(gòu)的程序更好的構(gòu)建url用的?直接忽略它,設(shè)為null即可。params:這個(gè)對(duì)象里邊的屬性:值對(duì)會(huì)作為post/get的參數(shù)傳到服務(wù)器,非常有用。

reader: DataReader,將服務(wù)器返回的數(shù)據(jù)解析成Record的數(shù)組。下面會(huì)有更詳細(xì)的解釋。

callback:當(dāng)讀取到服務(wù)器數(shù)據(jù)之后執(zhí)行的函數(shù)。這個(gè)函數(shù)接受三個(gè)參數(shù),分別是: r Ext.Record[],服務(wù)器端返回的經(jīng)過reader的數(shù)組。這是官方的說法,實(shí)際測(cè)試下來似乎只有當(dāng)action是read的時(shí)候才是這樣,下面有介紹;options:就是arg參數(shù)的值。success:是否成功的標(biāo)致,bool,這個(gè)也是服務(wù)器端返回的。

scope:作用域

arg:一些附加的參數(shù),會(huì)被傳到callback的options參數(shù)中。

下面我們來完成一個(gè)例子,利用httpproxy完成基本的CRUD操作。先看服務(wù)器端代碼:
復(fù)制代碼 代碼如下:

<%@ 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; }
}
}
}

我們用一個(gè)靜態(tài)的List來模仿數(shù)據(jù)庫(kù)。在處理函數(shù)中分別應(yīng)對(duì)4種情況。上面僅實(shí)現(xiàn)了read的代碼,返回一個(gè)數(shù)組,因?yàn)槲覀冏罱K客戶端采用ArrayReader來解析數(shù)據(jù)。服務(wù)器端的代碼沒什么好解釋的,很簡(jiǎn)單,再看客戶端的:
復(fù)制代碼 代碼如下:

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

這里有些東西要解釋下,首先是定義了一個(gè)Student的Record,這個(gè)和服務(wù)器端的代碼是一致的。然后定義了ArrayReader,ArrayReader是讀取數(shù)組內(nèi)的數(shù)據(jù),數(shù)據(jù)格式參考服務(wù)器端的代碼,它有一個(gè)root屬性非常重要,指定的是讀取json數(shù)據(jù)中哪個(gè)屬性的值(這個(gè)值是一個(gè)數(shù)組的字面量).idIndex也是必須指定的,它標(biāo)志著哪個(gè)字段是主鍵。fields就好理解了,讀取的Record的字段。數(shù)組里邊的順序要和Record的字段順序?qū)?yīng),否則可以通過Record的mapping屬性來指定,例如: {name:'Telephone',mapping:4}就表示讀取數(shù)組中第4個(gè)數(shù)值放到Telephone字段中。 下面就是定義httpProxy,設(shè)置好api。然后我們創(chuàng)建一個(gè)表單:

image

添加4個(gè)按鈕。先為Read按鈕寫上處理函數(shù):doRequest的一個(gè)參數(shù)是'read',第二個(gè)參數(shù)是null,因?yàn)槲也欢惺裁从?;第三個(gè)參數(shù)把要查詢的ID的值傳給服務(wù)器,第四個(gè)參數(shù)是一個(gè)reader,第五個(gè)參數(shù)callback很重要,我們?cè)谶@里處理服務(wù)器的返回值。注意,我在最后一個(gè)參數(shù)設(shè)置為arrayReader,于是這個(gè)函數(shù)的option參數(shù)的值實(shí)際上就是arrayReader。我為什么要這樣做呢,一來是做個(gè)演示,最后一個(gè)參數(shù)有什么用,二來是因?yàn)锳rrayReader比較古怪,注意它沒有公開的successProperty配置項(xiàng),也就是說它無法判斷服務(wù)器返回的success屬性,也就是這個(gè)callback的success參數(shù)永遠(yuǎn)是undefined!我一開始以為是我服務(wù)器端的代碼不對(duì),后來debug進(jìn)源代碼,發(fā)現(xiàn)它確實(shí)不處理這個(gè)success屬性?;蛟SArrayReader設(shè)計(jì)的本意就不是用在這個(gè)環(huán)境里的。不過作為演示,那就這樣用吧。其實(shí)它不處理success參數(shù)我們自己還是可以處理的。arrayReader內(nèi)部有個(gè)arrayData屬性,它是一個(gè)解析好的json對(duì)象,如果返回的json字符串中有success屬性那么這個(gè)對(duì)象也有success屬性,這樣我們就可以獲得服務(wù)器的返回值,同理,也可以處理服務(wù)器返回的任何數(shù)據(jù)。當(dāng)然,這種用法是文檔上沒有的,僅供演示。這個(gè)callback的第一個(gè)參數(shù),要特別注意,文檔上說是Record[],不過實(shí)際上它是一個(gè)對(duì)象,它的record屬性才是Record[]。我只能說extjs這部分的文檔很糟糕。幸好這部分的代碼是很不錯(cuò)的,有興趣的朋友可以調(diào)試進(jìn)去看看,以便有更深刻的理解。好了,萬事俱備,點(diǎn)擊下Read按鈕,結(jié)果出來了:

image

此文暫告一段落,其他幾個(gè)操作原理上類似的,突然發(fā)現(xiàn),如果單純的用這個(gè)例子來演示似乎不太合適。因?yàn)镈elete和Update服務(wù)器端都不需要返回什么數(shù)據(jù),而doRequest強(qiáng)制要求用一個(gè)DataReader來解析返回的數(shù)據(jù),很不方便?;蛟S在操作表格型的數(shù)據(jù)的時(shí)候doRequest的其他方法才有用武之地。針對(duì)單個(gè)對(duì)象的CRUD,可以直接采用更底層的Ext.ajax方法(另文介紹),或者利用表單的方法來處理。

本文只是對(duì)Extjs的數(shù)據(jù)模型的功能和原理做一簡(jiǎn)單的介紹,在實(shí)際中如何高效的組織代碼和在服務(wù)器與客戶端間傳遞數(shù)據(jù)是一個(gè)另外的話題。Extjs還是很靈活的,客戶端和服務(wù)器端的通信契約還是可以讓程序員自己決定。

太長(zhǎng)了…轉(zhuǎn)下篇…

相關(guān)文章

最新評(píng)論