Jul
26
[转]Spry框架初步入门
这篇文章在之前的日志中我曾经提过,虽然大部分的内容都可以在Spry API的说明中找到,但我觉得这20个知识点还是相当常用的,特转载过来。
Adobe的Ajax框架spry的正式版还没放出,所以文档是少之又少,在这里接合自己使用的情况总结20个spry的知识点给大家,相信会对大家有一定帮助,至少大家也会对spry有个初步的认识了,这个轻量型的框架就一个字:“易用”。
1. 使用spry框架,必须引用的两个核心js文件
2. 创建一个数据器dataset
method:为请求发送方式,POST / GET ;默认为GET
postData:为请求参数,可省略,可直接把"/photos.php"换成/photos.php?galleryid=2000&offset=20&limit=10
Content-Type:为头信息
3. 不使用缓存
这里要重点说明一下,我在应用时,曾经发现设置不用缓存时,页面仍然不是最新数据,我是用一个servlet生成xml,然后对生成的数据进行删除和添加,但页面显示的数据不会自动更新。
后来在adobe的官方论坛上找到了答案,在IE中,使用userCache:false是不够的,还要在生成xml的jsp,php等中设置头不使用cache,如在生成xml的jsp/servlet中是要加上:
response.addHeader("Cache-Control","no-cache");
以上问题只存在IE中,在firefox和opera中不存在。注,spry对opera9版本支持很好,使用版本8的朋友要注意了。
另外,也可以在构造完数据器后,再设置缓存:
4. 获取数据形式
假如我们上面的请求,返回的xml如下:
那么“gallery/photos/photo”返回的数据是下面的数组:
JavaScript代码:
5. 排序
6. 去除重复
7. 设置过滤器
8. 自动刷新,以毫秒为单位
9. 把类注册成观察器
10. 把函数方法注册为观察器
11. 动态区域块
所有使用Spry动态区域块的HTML页面都要在它们的<html>标签中加入xmlns:spry=http://ns.adobe.com/spry
COL, COLGROUP, FRAMESET, HTML, IFRAME, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR 不能设为动态区域
12. 数据引用
13. 循环
14. if 条件
15. 状态
16. 通过对象将区域注册成观察者
17. 以函数将区域注册成观察者
18. 主细节模式,同一数据器
19. 主细节模式,多个数据器
20. 改变数据源
Adobe的Ajax框架spry的正式版还没放出,所以文档是少之又少,在这里接合自己使用的情况总结20个spry的知识点给大家,相信会对大家有一定帮助,至少大家也会对spry有个初步的认识了,这个轻量型的框架就一个字:“易用”。
1. 使用spry框架,必须引用的两个核心js文件
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
2. 创建一个数据器dataset
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php", "/gallery/photos/photo", { method: "POST", postData: "galleryid=2000&offset=20&limit=10", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" } });
var dsPhotos2 = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
var dsPhotos2 = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
method:为请求发送方式,POST / GET ;默认为GET
postData:为请求参数,可省略,可直接把"/photos.php"换成/photos.php?galleryid=2000&offset=20&limit=10
Content-Type:为头信息
3. 不使用缓存
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { useCache: false })
这里要重点说明一下,我在应用时,曾经发现设置不用缓存时,页面仍然不是最新数据,我是用一个servlet生成xml,然后对生成的数据进行删除和添加,但页面显示的数据不会自动更新。
后来在adobe的官方论坛上找到了答案,在IE中,使用userCache:false是不够的,还要在生成xml的jsp,php等中设置头不使用cache,如在生成xml的jsp/servlet中是要加上:
response.addHeader("Cache-Control","no-cache");
以上问题只存在IE中,在firefox和opera中不存在。注,spry对opera9版本支持很好,使用版本8的朋友要注意了。
另外,也可以在构造完数据器后,再设置缓存:
dsData.useCache = false;
dsData.loadData();
dsData.loadData();
4. 获取数据形式
假如我们上面的请求,返回的xml如下:
引用
<gallery id="12345">
<photographer id="4532">John Doe</photographer>
<email>john@doe.com</email>
<photos id="2000">
<photo path="sun.jpg" width="16" height="16" />
<photo path="tree.jpg" width="16" height="16" />
<photo path="surf.jpg" width="16" height="16" />
</photos>
</gallery>
<photographer id="4532">John Doe</photographer>
<email>john@doe.com</email>
<photos id="2000">
<photo path="sun.jpg" width="16" height="16" />
<photo path="tree.jpg" width="16" height="16" />
<photo path="surf.jpg" width="16" height="16" />
</photos>
</gallery>
那么“gallery/photos/photo”返回的数据是下面的数组:
引用
[
{ "@path": "sun.jpg", "@width": 16, "@height": 16 },
{ "@path": "tree.jpg", "@width": 16, "@height": 16 },
{ "@path": "surf.jpg", "@width": 16, "@height": 16 }
]
{ "@path": "sun.jpg", "@width": 16, "@height": 16 },
{ "@path": "tree.jpg", "@width": 16, "@height": 16 },
{ "@path": "surf.jpg", "@width": 16, "@height": 16 }
]
JavaScript代码:
var rows = dsPhotos.getData(); // 获取所有行.
var path = rows[0]["@path"]; // 获取第一行中"@path"的值
dsPhotos.setCurrentRowNumber(2); // 将第3行做为当前处理行,下标以0开始
var id = dsPhotos.getData()[2]["ds_RowID"]; // 获取第3行的ID.
dsPhotos.setCurrentRow(id); // 通过第3行的id,将第3行设为当前处理行.
var path = rows[0]["@path"]; // 获取第一行中"@path"的值
dsPhotos.setCurrentRowNumber(2); // 将第3行做为当前处理行,下标以0开始
var id = dsPhotos.getData()[2]["ds_RowID"]; // 获取第3行的ID.
dsPhotos.setCurrentRow(id); // 通过第3行的id,将第3行设为当前处理行.
5. 排序
dsPhotos.sort("@path"); //以"@path"列的值为关健字对行排序
dsPhotos.sort("@path", "toggle"); //"ascending", "descending"和"toggle",默认是 "ascending"。
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { sortOnLoad: "@path", sortOrderOnLoad: "descending" });//也可在数据构造器中设置初始排序
dsPhotos.setColumnType("@width", "number");//设置类型
dsPhotos.setColumnType("@height", "number");
...
dsPhotos.sort("@width"); // 对 "@width" 列数据进行排序.
dsPhotos.sort("@path", "toggle"); //"ascending", "descending"和"toggle",默认是 "ascending"。
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { sortOnLoad: "@path", sortOrderOnLoad: "descending" });//也可在数据构造器中设置初始排序
dsPhotos.setColumnType("@width", "number");//设置类型
dsPhotos.setColumnType("@height", "number");
...
dsPhotos.sort("@width"); // 对 "@width" 列数据进行排序.
6. 去除重复
dsPhotos.distinct(); // Remove all duplicate rows.
//distinct()方法是具有破坏性的,多余的行是被删掉的,如果你想再得到所有的包括重复的原始项就得重新载入XML数据。
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { distinctOnLoad: true });//可在构造时预设
//distinct()方法是具有破坏性的,多余的行是被删掉的,如果你想再得到所有的包括重复的原始项就得重新载入XML数据。
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { distinctOnLoad: true });//可在构造时预设
7. 设置过滤器
var myFilterFunc = function(dataSet, row, rowNumber)
{
if (row["@path"].search(/^s/) != -1) //只返回以s开头的行
return row; // Return the row to keep it in the data set.
return null; // Return null to remove the row from the data set.
}
dsPhotos.filterData(myFilterFunc); // Filter the rows in the data set.
dsPhotos.filter(myFilterFunc); // 不破坏数据,是建一个新的数组
dsPhotos.filterData(null); // 取消过滤.
{
if (row["@path"].search(/^s/) != -1) //只返回以s开头的行
return row; // Return the row to keep it in the data set.
return null; // Return null to remove the row from the data set.
}
dsPhotos.filterData(myFilterFunc); // Filter the rows in the data set.
dsPhotos.filter(myFilterFunc); // 不破坏数据,是建一个新的数组
dsPhotos.filterData(null); // 取消过滤.
8. 自动刷新,以毫秒为单位
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { useCache: false, loadInterval: 10000 });//在构造器设置
dsPhotos.startLoadInterval(10000); // 设置自动刷新
...
dsPhotos.stopLoadInterval(); // 停止自动刷新
dsPhotos.startLoadInterval(10000); // 设置自动刷新
...
dsPhotos.stopLoadInterval(); // 停止自动刷新
9. 把类注册成观察器
var myObserver = new Object;
myObserver.onDataChanged = function(dataSet, data) //可支持:onPreLoad / onPostLoad / onLoadError / onDataChanged / onPreSort / onPostSort / onCurrentRowChanged
//第一个是发送通知的对象,做为数据器观察器,这个值永远都是dataSet对象。第二个参数可以不定义,也可以是一个对象(内置对象)
{
alert("onDataChanged called!";
};
dsPhotos.addObserver(myObserver);
dsPhotos.removeObserver(myObserver);
myObserver.onDataChanged = function(dataSet, data) //可支持:onPreLoad / onPostLoad / onLoadError / onDataChanged / onPreSort / onPostSort / onCurrentRowChanged
//第一个是发送通知的对象,做为数据器观察器,这个值永远都是dataSet对象。第二个参数可以不定义,也可以是一个对象(内置对象)
{
alert("onDataChanged called!";
};
dsPhotos.addObserver(myObserver);
dsPhotos.removeObserver(myObserver);
10. 把函数方法注册为观察器
function myObserverFunc(notificationType, dataSet, data) //notfication,是通知器类型,dataSet是数据器对象,data是要观察的数据
{
if (notificationType == "onDataChanged")
alert("onDataChanged called!";
else if (notificationType == "onPostSort")
alert("onPostSort called!";
};
dsPhotos.addObserver(myObserverFunc);
{
if (notificationType == "onDataChanged")
alert("onDataChanged called!";
else if (notificationType == "onPostSort")
alert("onPostSort called!";
};
dsPhotos.addObserver(myObserverFunc);
11. 动态区域块
所有使用Spry动态区域块的HTML页面都要在它们的<html>标签中加入xmlns:spry=http://ns.adobe.com/spry
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
.... ....
.... ....
<ul spry:region="dsPhotos">
<li>{dsPhotos::path}</li>
</ul>
.... ....
.... ....
<ul spry:region="dsPhotos">
<li>{dsPhotos::path}</li>
</ul>
COL, COLGROUP, FRAMESET, HTML, IFRAME, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR 不能设为动态区域
12. 数据引用
引用
{<数据器名>::<数据器列名>}
如果一个动态区域块只和一个数据器相关联,则你甚至可以省略掉数据器的名字
<li>{@path}</li>
ds_RowID - 这是数据器的行id。这个id可以帮我们指定数据器中的一个数据。它和数据是对应的,即使数据执行了排序操作,这个id和数据的对应关系也不会变化。
ds_RowNumber - 这是数据器当前数据的行号。
ds_RowNumberPlus1 - 这个与上面的ds_RowNumber相同,只不过它规定了数据的行号从1开始,而不是从0开始。
ds_RowCount - 它是数据器中数据的行的数量。如果使用了一个非破坏性的过滤器,则它的值是这个过滤器执行后得到的行的数量。
ds_UnfilteredRowCount - 在执行非破坏性过滤器前,数据器中行的数量。
ds_CurrentRowID - 当前行的id。这个值不会改变,除非使用了一个循环的构造。
ds_CurrentRowNumber - 当前行的行号。这个值不会改变,除非使用了一个循环的构造。
ds_SortColumn - 上一次排序所依赖的列名。如果这个数据器的数据还未进行过排序,则返回一个空字符串。
ds_SortOrder - 数据器中数据排序的参数,将返回三种字符串"ascending", "descending", 或空字符串.。
ds_EvenOddRow - 它返回的是"even"或"odd",告诉我们ds_RowNumber的值是奇数还是偶数。
如果一个动态区域块只和一个数据器相关联,则你甚至可以省略掉数据器的名字
<li>{@path}</li>
ds_RowID - 这是数据器的行id。这个id可以帮我们指定数据器中的一个数据。它和数据是对应的,即使数据执行了排序操作,这个id和数据的对应关系也不会变化。
ds_RowNumber - 这是数据器当前数据的行号。
ds_RowNumberPlus1 - 这个与上面的ds_RowNumber相同,只不过它规定了数据的行号从1开始,而不是从0开始。
ds_RowCount - 它是数据器中数据的行的数量。如果使用了一个非破坏性的过滤器,则它的值是这个过滤器执行后得到的行的数量。
ds_UnfilteredRowCount - 在执行非破坏性过滤器前,数据器中行的数量。
ds_CurrentRowID - 当前行的id。这个值不会改变,除非使用了一个循环的构造。
ds_CurrentRowNumber - 当前行的行号。这个值不会改变,除非使用了一个循环的构造。
ds_SortColumn - 上一次排序所依赖的列名。如果这个数据器的数据还未进行过排序,则返回一个空字符串。
ds_SortOrder - 数据器中数据排序的参数,将返回三种字符串"ascending", "descending", 或空字符串.。
ds_EvenOddRow - 它返回的是"even"或"odd",告诉我们ds_RowNumber的值是奇数还是偶数。
13. 循环
//方式一:
<li spry:repeat="dsPhotos">{@path}</li>
//方式二:
<ul spry:repeatchildren="dsPhotos">
<li>{@path}</li>
</ul>
//只输出以s开头的 spry:test属性的值可以是任何等于0或非0值的JavaScript表达示。如果这个表达示返回非0值,这个内容将会被输出,相当于if <>0就输出后面元素。
<li spry:repeat="dsPhotos" spry:test="'{@path}'.search(/^s/) != -1;">{@path}</li>
<li spry:repeat="dsPhotos">{@path}</li>
//方式二:
<ul spry:repeatchildren="dsPhotos">
<li>{@path}</li>
</ul>
//只输出以s开头的 spry:test属性的值可以是任何等于0或非0值的JavaScript表达示。如果这个表达示返回非0值,这个内容将会被输出,相当于if <>0就输出后面元素。
<li spry:repeat="dsPhotos" spry:test="'{@path}'.search(/^s/) != -1;">{@path}</li>
14. if 条件
<li spry:if="'{@path}'.search(/^s/) != -1;">{@path}</li>
//if/else的形式,要使用"spry:choose"属性
<div spry:choose="spry:choose">
<div spry:when="'{@path}' == 'surf.gif'">{@path}</div>
<div spry:when="'{@path}' == 'undefined'">Path was not defined.</div>
<div spry:default="spry:default">Unexpected value for path!</div>
</div>
//if/else的形式,要使用"spry:choose"属性
<div spry:choose="spry:choose">
<div spry:when="'{@path}' == 'surf.gif'">{@path}</div>
<div spry:when="'{@path}' == 'undefined'">Path was not defined.</div>
<div spry:default="spry:default">Unexpected value for path!</div>
</div>
15. 状态
<div spry:region="dsEmployees">
<div spry:state="loading">正在载入数据 ...</div>
<div spry:state="error">数据载入失败!</div>
<ul spry:state="ready">
<li spry:repeat="dsEmployees">{firstname} {lastname}</li>
</ul>
</div>
<div spry:state="loading">正在载入数据 ...</div>
<div spry:state="error">数据载入失败!</div>
<ul spry:state="ready">
<li spry:repeat="dsEmployees">{firstname} {lastname}</li>
</ul>
</div>
16. 通过对象将区域注册成观察者
myObserver = new Object;
myObserver.onPostUpdate = function(notifier, data)
{
alert("onPostUpdate called for " + data.regionID);
};
...
// 调用addObserver() 将类注册为观察者.
Spry.Data.Region.addObserver("employeeListRegion", myObserver);
...
//注销
Spry.Data.Region.removeObserver("employeeListRegion", myObserver);
...
<ul id="employeeListRegion" spry:region="dsEmployees">
...
</ul>
myObserver.onPostUpdate = function(notifier, data)
{
alert("onPostUpdate called for " + data.regionID);
};
...
// 调用addObserver() 将类注册为观察者.
Spry.Data.Region.addObserver("employeeListRegion", myObserver);
...
//注销
Spry.Data.Region.removeObserver("employeeListRegion", myObserver);
...
<ul id="employeeListRegion" spry:region="dsEmployees">
...
</ul>
17. 以函数将区域注册成观察者
function myRegionCallback(notificationState, notifier, data)
{
if (notificationType == "onPreUpdate") //onLoadingData / onPreUpdate / onPostUpdate / onError
alert(regionID + " is starting an update!");
else if (notificationType == "onPostUpdate")
alert(regionID + " is done updating!");
}
...
// 注册
Spry.Data.Region.addObserver("employeeListRegion", MyRegionCallback);
...
// 注销
Spry.Data.Region.removeObserver("employeeListRegion", MyRegionCallback);
...
<ul id="employeeListRegion" spry:region="dsEmployees">
...
</ul>
{
if (notificationType == "onPreUpdate") //onLoadingData / onPreUpdate / onPostUpdate / onError
alert(regionID + " is starting an update!");
else if (notificationType == "onPostUpdate")
alert(regionID + " is done updating!");
}
...
// 注册
Spry.Data.Region.addObserver("employeeListRegion", MyRegionCallback);
...
// 注销
Spry.Data.Region.removeObserver("employeeListRegion", MyRegionCallback);
...
<ul id="employeeListRegion" spry:region="dsEmployees">
...
</ul>
18. 主细节模式,同一数据器
<span spry:region="dsEmployees">
<select spry:repeatchildren="dsEmployees" onchange="dsEmployees.setCurrentRow(this.value)">
<option spry:if="{ds_RowNumber} == 0" value="{ds_RowID}" selected="selected">{username}</option>
<option spry:if="{ds_RowNumber} != 0" value="{ds_RowID}">{username}</option>
</select>
</span>
<span spry:detailregion="dsEmployees">{@id} - {firstname} {lastname} - {phone} </span>
//spry:detailregion"会在接收到"CurrentRowChanged"通知后改变自己的展示形式。
<select spry:repeatchildren="dsEmployees" onchange="dsEmployees.setCurrentRow(this.value)">
<option spry:if="{ds_RowNumber} == 0" value="{ds_RowID}" selected="selected">{username}</option>
<option spry:if="{ds_RowNumber} != 0" value="{ds_RowID}">{username}</option>
</select>
</span>
<span spry:detailregion="dsEmployees">{@id} - {firstname} {lastname} - {phone} </span>
//spry:detailregion"会在接收到"CurrentRowChanged"通知后改变自己的展示形式。
19. 主细节模式,多个数据器
var dsStates = new Spry.Data.XMLDataSet("../../data/states/states.xml", "states/state");
var dsCities = new Spry.Data.XMLDataSet("../../data/states/{dsStates::url}", "state/cities/city");
//两个数据器有依赖关系,也可以用:"/webapp/cities.php?stateid={dsStates::@id}".
<form name="selectForm">
//State:
<span spry:region="dsStates" id="stateSelector">
<select spry:repeatchildren="dsStates" name="stateSelect" onchange="document.forms[0].citySelect.disabled = true; dsStates.setCurrentRow(this.value);">
<option spry:if="{ds_RowNumber} == 0" value="{ds_RowID}" selected="selected">{name}</option>
<option spry:if="{ds_RowNumber} != 0" value="{ds_RowID}">{name}</option>
</select>
</span>
//City:
<span spry:region="dsCities" id="citySelector">
<select spry:repeatchildren="dsCities" name="citySelect">
<option spry:if="{ds_RowNumber} == 0" value="{name}" selected="selected">{name}</option>
<option spry:if="{ds_RowNumber} != 0" value="{name}">{name}</option>
</select>
</span>
</form>
var dsCities = new Spry.Data.XMLDataSet("../../data/states/{dsStates::url}", "state/cities/city");
//两个数据器有依赖关系,也可以用:"/webapp/cities.php?stateid={dsStates::@id}".
<form name="selectForm">
//State:
<span spry:region="dsStates" id="stateSelector">
<select spry:repeatchildren="dsStates" name="stateSelect" onchange="document.forms[0].citySelect.disabled = true; dsStates.setCurrentRow(this.value);">
<option spry:if="{ds_RowNumber} == 0" value="{ds_RowID}" selected="selected">{name}</option>
<option spry:if="{ds_RowNumber} != 0" value="{ds_RowID}">{name}</option>
</select>
</span>
//City:
<span spry:region="dsCities" id="citySelector">
<select spry:repeatchildren="dsCities" name="citySelect">
<option spry:if="{ds_RowNumber} == 0" value="{name}" selected="selected">{name}</option>
<option spry:if="{ds_RowNumber} != 0" value="{name}">{name}</option>
</select>
</span>
</form>
20. 改变数据源
<select onchange="dsEmployees.setURL(this.value); dsEmployees.loadData();">
<option value="../../data/employees-01.xml" selected>Set 1</option>
<option value="../../data/employees-02.xml">Set 2</option>
</select>
<th scope="col" onclick="dsEmployees.sort('@id');">Employee ID </th>
<option value="../../data/employees-01.xml" selected>Set 1</option>
<option value="../../data/employees-02.xml">Set 2</option>
</select>
<th scope="col" onclick="dsEmployees.sort('@id');">Employee ID </th>