|
數(shù)據(jù)記錄 Record
數(shù)據(jù)集合中的一個條記錄,包括數(shù)據(jù)的定義和值。相當于實體類。
數(shù)據(jù)代理 Proxy
用來獲取數(shù)據(jù)的代理。相當于Datasource。
數(shù)據(jù)解析器 DataReader
負責將Proxy獲取的數(shù)據(jù)解析出來傳換成Record并存入Store中。相當于C#的DataReader。
數(shù)據(jù)集 Store
一個保存數(shù)據(jù)的集合,類似于C#的Datatable。
Extjs3的Proxy較以前版本有了一些變動,資料很少,而且官方文檔上相當簡練,以至于一個完整的例子都沒有…… 我盡力理解……
1. 數(shù)據(jù)記錄
一條數(shù)據(jù)記錄一般是有多個字段組成的。字段由Ext.data.Field類定義。Field的配置項很豐富,使我們有足夠的信息在弱類型的語言中處理我們的數(shù)據(jù),主要有:
name:字段名;defaultValue:默認值;type:數(shù)據(jù)類型,可以是string,int,float,boolean,date和auto(默認)。先介紹這么多,其余的在具體用到的時候再介紹。
要建立一個數(shù)據(jù)記錄類(注意不是具體一條數(shù)據(jù)),可以使用Ext.data.Record.create方法,這個方法接受一個數(shù)組的Field類的配置項,返回一個構(gòu)造函數(shù)。看一個例子:
復制代碼 代碼如下:
<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幾乎把前臺開發(fā)變成了后臺。這些內(nèi)容等介紹Store的時候再介紹。
2.數(shù)據(jù)代理
Ext.data.DataProxy是數(shù)據(jù)代理的抽象基類,實現(xiàn)了DataProxy的通用公共接口。DataProxy的最重要的通用方法就是doRequest,執(zhí)行這個方法之后將從各種具體的數(shù)據(jù)源讀取數(shù)據(jù)。繼承自DataProxy的具體Proxy類有:
2.1 HttpProxy
這是最常用的proxy,通過一個http請求從遠程服務(wù)器獲取數(shù)據(jù)。HttpProxy最重要的配置項就是配置獲取數(shù)據(jù)的url。HttpProxy不僅僅支持獲取數(shù)據(jù),它支持對數(shù)據(jù)的CRUD操作。DataProxy的api屬性就是用來配置這4種操作對應(yīng)的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后,就可以執(zhí)行doRequest方法,doRequest方法的參數(shù)比較復雜:
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)這個參數(shù)有什么用…… 看源代碼發(fā)現(xiàn)其中出現(xiàn)了這樣的表達式 url+rs.id,這個或許是為MVC架構(gòu)的程序更好的構(gòu)建url用的?直接忽略它,設(shè)為null即可。params:這個對象里邊的屬性:值對會作為post/get的參數(shù)傳到服務(wù)器,非常有用。
reader: DataReader,將服務(wù)器返回的數(shù)據(jù)解析成Record的數(shù)組。下面會有更詳細的解釋。
callback:當讀取到服務(wù)器數(shù)據(jù)之后執(zhí)行的函數(shù)。這個函數(shù)接受三個參數(shù),分別是: r Ext.Record[],服務(wù)器端返回的經(jīng)過reader的數(shù)組。這是官方的說法,實際測試下來似乎只有當action是read的時候才是這樣,下面有介紹;options:就是arg參數(shù)的值。success:是否成功的標致,bool,這個也是服務(wù)器端返回的。
scope:作用域
arg:一些附加的參數(shù),會被傳到callback的options參數(shù)中。
下面我們來完成一個例子,利用httpproxy完成基本的CRUD操作。先看服務(wù)器端代碼:
復制代碼 代碼如下:
<%@ 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; }
}
}
}
我們用一個靜態(tài)的List來模仿數(shù)據(jù)庫。在處理函數(shù)中分別應(yīng)對4種情況。上面僅實現(xiàn)了read的代碼,返回一個數(shù)組,因為我們最終客戶端采用ArrayReader來解析數(shù)據(jù)。服務(wù)器端的代碼沒什么好解釋的,很簡單,再看客戶端的:
復制代碼 代碼如下:
<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,這個和服務(wù)器端的代碼是一致的。然后定義了ArrayReader,ArrayReader是讀取數(shù)組內(nèi)的數(shù)據(jù),數(shù)據(jù)格式參考服務(wù)器端的代碼,它有一個root屬性非常重要,指定的是讀取json數(shù)據(jù)中哪個屬性的值(這個值是一個數(shù)組的字面量).idIndex也是必須指定的,它標志著哪個字段是主鍵。fields就好理解了,讀取的Record的字段。數(shù)組里邊的順序要和Record的字段順序?qū)?yīng),否則可以通過Record的mapping屬性來指定,例如: {name:'Telephone',mapping:4}就表示讀取數(shù)組中第4個數(shù)值放到Telephone字段中。 下面就是定義httpProxy,設(shè)置好api。然后我們創(chuàng)建一個表單:
添加4個按鈕。先為Read按鈕寫上處理函數(shù):doRequest的一個參數(shù)是'read',第二個參數(shù)是null,因為我不懂它有什么用;第三個參數(shù)把要查詢的ID的值傳給服務(wù)器,第四個參數(shù)是一個reader,第五個參數(shù)callback很重要,我們在這里處理服務(wù)器的返回值。注意,我在最后一個參數(shù)設(shè)置為arrayReader,于是這個函數(shù)的option參數(shù)的值實際上就是arrayReader。我為什么要這樣做呢,一來是做個演示,最后一個參數(shù)有什么用,二來是因為ArrayReader比較古怪,注意它沒有公開的successProperty配置項,也就是說它無法判斷服務(wù)器返回的success屬性,也就是這個callback的success參數(shù)永遠是undefined!我一開始以為是我服務(wù)器端的代碼不對,后來debug進源代碼,發(fā)現(xiàn)它確實不處理這個success屬性。或許ArrayReader設(shè)計的本意就不是用在這個環(huán)境里的。不過作為演示,那就這樣用吧。其實它不處理success參數(shù)我們自己還是可以處理的。arrayReader內(nèi)部有個arrayData屬性,它是一個解析好的json對象,如果返回的json字符串中有success屬性那么這個對象也有success屬性,這樣我們就可以獲得服務(wù)器的返回值,同理,也可以處理服務(wù)器返回的任何數(shù)據(jù)。當然,這種用法是文檔上沒有的,僅供演示。這個callback的第一個參數(shù),要特別注意,文檔上說是Record[],不過實際上它是一個對象,它的record屬性才是Record[]。我只能說extjs這部分的文檔很糟糕。幸好這部分的代碼是很不錯的,有興趣的朋友可以調(diào)試進去看看,以便有更深刻的理解。好了,萬事俱備,點擊下Read按鈕,結(jié)果出來了:
此文暫告一段落,其他幾個操作原理上類似的,突然發(fā)現(xiàn),如果單純的用這個例子來演示似乎不太合適。因為Delete和Update服務(wù)器端都不需要返回什么數(shù)據(jù),而doRequest強制要求用一個DataReader來解析返回的數(shù)據(jù),很不方便。或許在操作表格型的數(shù)據(jù)的時候doRequest的其他方法才有用武之地。針對單個對象的CRUD,可以直接采用更底層的Ext.ajax方法(另文介紹),或者利用表單的方法來處理。
本文只是對Extjs的數(shù)據(jù)模型的功能和原理做一簡單的介紹,在實際中如何高效的組織代碼和在服務(wù)器與客戶端間傳遞數(shù)據(jù)是一個另外的話題。Extjs還是很靈活的,客戶端和服務(wù)器端的通信契約還是可以讓程序員自己決定。
太長了…轉(zhuǎn)下篇…
JavaScript技術(shù):Extjs學習筆記之九 數(shù)據(jù)模型(上),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。