Spry 数据集和动态区概览

注意: 这个文档是Spry框架的基本概览。它没有涵盖框架的所有功能。请查看 Data API

Spry框架是做什么的?

Spry 框架是一套包含JavaScript,CSS,和一些图片文件的客户端JavaScript库。支持XML数据集,动态区域,组件,动画效果。

Browser Diagram

图 - Spry 框架运行在客户端浏览器上。

虽然这些文件存放在服务器上,实际上是被加载到浏览器中运行的。框架的用户将所有需要的文件链接到HTML文档中,以使用不同的组件,来获得更丰富的用户体验。

Spry 框架 是和设计人员紧密相关的,因此框架中的每个元素都要遵循以下原则:

  • 保持轻便
  • 保持简洁
    • 使用标准的技术,HTML,CSS,JavaScript。
    • 保持私有属性和语法最少化。
    • 尽可能减少教本编程。

返回


XML Data Sets(XML数据集)

XML数据集是一个提供加载XML数据API的JavaScript对象。当数据加载完成后,被格式化成一个行和列组成的数据表。

对于你了解的XML数据集,请记住这只是一个预览版本,这个文档只是简单地描述了当前的实现。数据集的API还在不停的完善中。

创建一个XML数据集

要创建一个XML数据集,HTML文件中必须包含两个JavaScript库文件:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
</head>
<body>
</body>
</html>

代码 - 要使用XML数据集和动态区域你必须在HTML中包含xpath.js 和 SpryData.js 文件。

"xpath.js" 是 Google 的XPath 1.0标准 JavaScript框架。要获得更详细的信息可以访问他们的开源项目google-ajaxslt project page. "SpryData.js" 包含了定义XML数据集和动态区域的代码。

XML数据集使用 JavaScript "new" 关键字创建. 构造函数有两个参数:

  • XML文件的URL
  • XPath描述了你要取得的数据节点。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>

</head>
<body>
</body>
</html>

代码 - 使用JavaScript创建XML数据集。第一个参数是XML的URL,第二个参数是数据的XPath路径。

URL参数可以是XML文件的绝对或相对地址,或者是一个返回XML数据的WEB服务接口。用户要注意XML数据要同HTML文件处在同一域下。开发人员通常使用一个服务器端的脚本调取不同域的数据。

数据集默认使用GET方式请求数据。当然也可以使用POST方式,这通过额外的参数设置。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

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" } });
</script>
</head>
<body>
</body>

</html>

代码 - 通过HTTP POST 方式取出XML数据

如果使用POST,但是没有定义内容类型,那么默认的内容类型将是"application/x-www-form-urlencoded; charset=UTF-8".

下面是HTTP相关的构造参数:

XML数据集构造函数参数选项
method
获取XML数据的方法 必须是"GET" 或 "POST".
postData
可以是一个包含 url encode 表单参数或者任何 XMLHttpRequest 对象支持的值。如果 "Content-Type" 头信息没有在POST数据中定义,将默认使用"application/x-www-form-urlencoded; charset=UTF-8" 类型。
username
在访问XML数据的时候服务器要求的用户名。
password
在访问XML数据的时候服务器要求的密码。
headers
用来存储HTTP请求头信息名值对信息的数组或对象。

值得注意的是当你使用 "new"方法创建数据集的时候,数据集中是没有数据的,你必须调用loadData()方法发送请求加载XML数据,这个加载是异步的,因此当你在调用loadData方法后立刻访问数据集的时候,其中的数据可能还是空的。

数据集使用 XMLHTTPRequest 对象异步调用URL,当XML数据达到的时候,它实际上有两种格式,文本格式和DOM树格式。

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

代码 - 文本格式的XML样例。

XML as Text

图例 - DOM树格式的XML样例

数据集给构造函数传递XPath参数,在XML DOM树中找到需要的数据节点。

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

代码 - 使用XPath选择数据 "/gallery/photos/photo".

XPath /gallery/photos/photo

图例 - 使用XPath选择数据 "/gallery/photos/photo".

数据集被扁平化为一张数据表:

@path @width @height
sun.jpg 16 16
tree.jpg 16 16
surf.jpg 16 16

图例 - 扁平化使用XPath选择的数据"/gallery/photos/photo".

表的列名称来自选择的数据节点或其子节点的标签名称及其属性。选中节点的每个属性都会被作为一列。如果选中的节点有一个单独的文本或CDATA子节点,那么这个子节点将作为其父节点的值。如果选择的节点有子节点,将为其所有值和属性创建列。

这些说明有些令人迷惑,因此来通过一些实例说明如何扁平化数据,如何生成列名。

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

代码 - 选择节点 XPath "/gallery/photographer".

XPath /gallery/photographer

图例 - 选择节点 XPath "/gallery/photographer".

一个 XPath "/gallery/photographer" 将生成下面的表格:

photographer @id
John Doe 16

图例 - 根据 XPath "/gallery/photographer"扁平化的数据

在这个案例中,只选择了一个节点,因此我们只能获得一个数据行。<photographer>节点值是文本"John Doe"因此生成一个名字为 "photographer" 的列来存储这个值。"id" 是 <photographer> 节点的一个属性,因此它的值被放在了"@id" 列。所有的属性名称都加有 "@" 前缀。

XPath "/gallery":

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

代码 - 选择 XPath 为 /gallery的节点。

XPath /gallery

图例 - 选择 XPath 为 /gallery的节点。

下面是生成的数据表:

@id photographer photographer/@id email
12345 John Doe 4532 john@doe.com

图例 - 选择XPath "/gallery"扁平化的数据。

注意子节点的属性生成的列名称前缀是这个子节点的标签名。在这个案例中, <photographer> 是一个<gallery>节点的子节点,因此它的 id 属性以 "photographer/@"前缀。还注意到没有任何<photos>节点的内容加到表中,尽管它也是<gallery> 节点的子节点。这是因为任何含有其他子节点的子节点(第二层子节点)不会被放在数据表中。

使用 XPath,你也可以选择节点的属性,因此如果你使用 XPath "gallery/photos/photo/@path":

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

代码 - 选择 XPath 为 "gallery/photos/photo/@path"的节点。

XPath /gallery/photos/photo

图例 - 选择 XPath 为 "gallery/photos/photo/@path"。

你将获得一个如下的表格:

@path
sun.jpg
tree.jpg
surf.jpg

图例 - 选择XPath "/gallery/photos/photo/@path"扁平化的数据。

返回

缓存

默认情况下,任何数据集调用的XML数据都被Spry缓存在客户端。如果一个数据集要加载的XML已经在缓存中,那么这个缓存的数据将被传个数据集。如果多个数据集试图同时调用同一个数据,所有的调用请求将被整合在一个单独的HTTP请求以节省带宽。

使用缓存和请求合并可以大大地提高性能,尤其是对于多个数据集调用同一个XML数据的时候,但是也有需要多次直接从服务器调用数据的时候。例如,对于每次返回的数据可能都是不同的情况,这就需要跳过缓存,通过设置XMLDataSet构造函数的参数"useCache"值为false。

Var dsPhotos = new  Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { useCache:  false })

代码 - 数据集中的数据是以有属性(列)的数据行对象数组来存储的。

返回

获得数据

上面所提及的,在XML数据加载后被扁平化为数据表。在数据集中,数据是以有属性(列)的数据行对象数组来存储的。

[
	{ "@path": "sun.jpg",  "@width": 16, "@height": 16 },
	{ "@path": "tree.jpg", "@width": 16, "@height": 16 },
	{ "@path": "surf.jpg", "@width": 16, "@height": 16 }
]
          
@path @width @height
sun.jpg 16 16
tree.jpg 16 16
surf.jpg 16 16

代码 - 数据集中的数据是以有属性(列)的数据行对象数组来存储的。

你可以通过调用 getData()获得数据集中的所有行。上面所提及的,数据是异步加载的,所以你只能在加载完成后访问数据。你可能需要注册一个侦听器来检测数据是否加载完毕。参看下面的侦听器部分。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...
var rows = dsPhotos.getData(); // 获得所有数据行
var path = rows[0]["@path"];   // 获得第一行"@path"列的数据

代码 - 使用 getData() 获得数据集的所有行。你可以通过定义列名取得数据行中的列值。

返回

当前行

每个数据集都提供一个 "current row"。默认的,当前行为数据集的第一行。可以通过调用setCurrentRowNumber()方法改变当前行。注意第一行的索引值是0,因此如果一个数据集有10行,那么最后一行的索引值是9。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

dsPhotos.setCurrentRowNumber(2); // 设置第三行为当前行。

代码 - 使用 setCurrentRowByNumber() 或者 setCurrentRow() 改变当前行。

数据集中的每一行都有一个标识符,可以通过此标识符引用此数据行。你可以通过访问"ds_RowID" 属性获得行的标识符。也可以通过调用setCurrentRow(),传递标识符给此函数以设定当前行。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

var id = dsPhotos.getData()[2]["ds_RowID"]; // 获得第三行的ID。

...

dsPhotos.setCurrentRow(id); // 使用ID设置第三行为当前行。

代码 - 你可以通过访问"ds_RowID" 属性获得行的标识符。 也可以通过调用setCurrentRow(),传递标识符给此函数以设定当前行。

返回

排序

你可以在数据集中使用给定的数据列的值对数据行进行排序。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

dsPhotos.sort("@path"); // 使用 "@path" 列进行排序。

代码 - 调用 sort() 方法可以以某个数据列对数据集升序排列

sort() 方法有两个参数。第一个参数可以是列名称,或者是一个列名称的数组。如果第一个参数是一个数组,数组的第一个元素将为主索引列,后面的每列依次为第二、第三等等索引列。第二个参数是排序方式,必须是下面的一个值: "ascending", "descending", "toggle"。如果第二个参数没有定义,默认的为升序排列。定义 "toggle" 是在升序或降序间切换。数据的初始状态为升序。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

dsPhotos.sort("@path", "toggle"); // 使用 "@path" 列作排序。

代码 - 调用 sort() 方法使用 "toggle" 在 "ascending" and "descending" 之间转换。

如果你要在数据加载后自动排序,可以在数据集构造函数中定义排序列,和排序方式。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { sortOnLoad: "@path", sortOrderOnLoad: "descending" });

代码 - 使用 "sortOnLoad" 选项在构造函数中定义要排序的列。这个示例中数据集将自动以 "@path" 列做降序排列。

默认情况数据集中的值都作为文本类型。这就会在对数字或日期值进行排序时出现问题。你可以在调用setColumnType()时 定义排序列的数据类型。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
dsPhotos.setColumnType("@width", "number");
dsPhotos.setColumnType("@height", "number");

...

dsPhotos.sort("@width"); // 使用 "@width" 列进行排序。

代码 - 使用 setColumnType() 定义给定数据列的数据类型。

现在支持的数据类型为 "number", "date", and "string"。

返回

排重

你可以使用distinct() 方法移除重复的数据行。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...


dsPhotos.distinct(); // 移除所有的数据行。

代码 - 使用distinct() 方法移除重复的数据行。

如果你要在数据集加载完成时自动运行 distinct() 方法 ,使用构造函数的"distinctOnLoad" 选项。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { distinctOnLoad: true });

代码 - 使用distinct() 方法移除重复的数据行。

用户应该知道distinct() 方法是具有破坏性的,它将丢弃重复的行。唯一取回丢弃数据的方法就是重新加载数据。

返回

过滤

数据集支持破坏性和非破坏性过滤。

在使用任意一种过滤方式之前,你必须提供一个过滤函数包含一个数据集,行对象,行号。这个函数将被数据集过滤方法调用,对每行进行过滤操作。你的函数必须返回传来的行对象,或者一个新的行对象,以替换传来的行对象。如果你的函数想过滤掉此行,它将返回一个null值。

数据集的破坏性过滤方法是 filterData()。这个方法将实际替换或丢弃数据集的行。唯一取回丢弃数据的方法就是重新加载数据。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

// 滤除所有@path列数据中不是以“S”开头的数据行

var myFilterFunc = function(dataSet, row, rowNumber)
{
	if (row["@path"].search(/^s/) != -1)
		return row;                     // 返回要保留的行
	return null;                        // 返回null移除数据行
}


dsPhotos.filterData(myFilterFunc); // 过滤数据行

代码 - 使用破坏性的 filterData() 方法永久的从数据集中移除数据行。

注意你的过滤器函数一直是起作用的,即使你从另一个URL调用新数据,除非你调用参数为 null的filterData()方法。

dsPhotos.filterData(null); // 关闭破坏性的过滤。

代码 - 调用参数为 null的filterData()方法卸载你的过滤功能。

数据集的非破坏性过滤方法是 filter()。不同于 filterData(), filter() 创建一个原数据的引用数组,因此只要你的过滤函数没有编辑传给它的数据行,你就可以通过调用参数为 null的filter()方法获得原数据。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

// 滤除所有@path列数据中不是以“S”开头的数据行
var myFilterFunc = function(dataSet, row, rowNumber)
{
	if (row["@path"].search(/^s/) != -1)
		return row;                     //  返回要保留的行
	return null;                        // 返回null移除数据行
}


dsPhotos.filter(myFilterFunc); // 过滤数据行

代码 - 使用非破坏性的 filter() 函数过滤数据。

dsPhotos.filter(null); // 关闭非破坏性的过滤。

代码 - 调用参数为 null的filter()方法卸载你的非破坏性过滤功能。

返回

数据自动刷新

数据集可以以毫秒为单位周期性重载数据。这使得数据定期变动的时候很方便。

当调用数据集构造函数时可以给出loadInterval选项的值,定期重载数据。

// 每十秒加载一次数据。关闭缓存以保证直接从服务器获取数据。
var dsPhotos = new  Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo", { useCache:  false, loadInterval: 10000 });

代码 - 当调用数据集构造函数时可以给出loadInterval选项的值。

你也可以使用 startLoadInterval() 方法打开定时重载, 使用stopLoadInterval() 方法关闭定时重载。

dsPhotos.startLoadInterval(10000); // 每十秒加载一次。

...

dsPhotos.stopLoadInterval(); // 关闭定时重载。

代码 - 你也可以使用 startLoadInterval() 方法打开定时重载, 使用stopLoadInterval() 方法关闭定时重载。

返回

侦听器

XML数据集支持一种监听机制,允许一个对象或函数接受事件通知。

XMLDataSet 通知
onPreLoad
数据集将要请求数据。如果一个数据集依赖于另一个数据集,这个事件通知将不会触发直到两个数据集都成功加载。
onPostLoad
数据请求成功。数据可以等待处理。
onLoadError
当请求数据时出现错误。
onDataChanged
数据集中的数据已经被修改。
onPreSort
数据集将要被排序。
onPostSort
数据集已经被排序。
onCurrentRowChanged
数据集当前行被改变。

对象作为侦听器

要接收通知,对象必须为每个通知定义相应的方法,然后在数据集上注册侦听器。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

var myObserver = new Object;
myObserver.onDataChanged = function(dataSet, data)
{
	alert("onDataChanged called!");
};

dsPhotos.addObserver(myObserver);

代码 - 一个 onDataChanged 通知对象必须定义一个 onDataChanged ()方法,然后调用 addObserver().

每个通知方法的第一个参数是发送通知的对象。因此对于数据集侦听器,通常是数据集对象。第二个参数可以是未定义,或一个基于通知类型的对象。

传入 XMLDataSet 通知的数据
onPreLoad
undefined
onPostLoad
undefined
onLoadError
Spry.Utils.loadURL.Request 对象在请求时被使用。
onDataChanged
undefined
onPreSort

对象有如下属性:

oldSortColumns:

最后一次排序使用到的列对象数组。

oldSortOrder: 最后一次排序顺序。
newSortColumns: 排列使用到的列对象数组。
newSortOrder: 使用的排序顺序。
onPostSort

对象有如下属性:

oldSortColumns:

上一次排序使用到的列对象数组。

oldSortOrder: 上一次排序顺序。
newSortColumns: 排列使用到的列对象数组。
newSortOrder: 使用的排序顺序。
onCurrentRowChanged

对象有如下属性:

oldRowID:

最后一次使用的当前行的 ds_RowID。

newRowID: 当前行的 ds_RowID。

要停止一个对象接收通知,对象必须从侦听器列表中删除,通过调用removeObserver().

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

dsPhotos.removeObserver(myObserver);

代码 -通过调用removeObserver()停止一个对象接收通知

函数作为侦听器

函数可以被注册为侦听器。对象侦听器和函数侦听器的主要区别是一个对象只接收定义了的类型的通知,然而函数侦听器将被每一种通知调用。

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...


function myObserverFunc(notificationType, dataSet, data)
{
	if (notificationType == "onDataChanged")
		alert("onDataChanged called!";
	else if (notificationType == "onPostSort")
		alert("onPostSort called!";
};

dsPhotos.addObserver(myObserverFunc);

代码 -函数可以被注册为侦听器

函数侦听器同样使用addObserver注册。

当函数被调用,第一个参数是通知类型,这是个通知名称的字符串。本例中第二个参数是数据集,第三个参数是通知的数据。

要停止一个对象接收通知,对象必须从侦听器列表中删除,通过调用removeObserver().

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

...

dsPhotos.removeObserver(myObserverFunc);

代码 -通过调用removeObserver()停止一个对象接收通知

返回


关于动态区域

动态区域是绑定了数据集的HTML区域,它可以在其数据改变时重新生成代码。

之所以可以自动生成代码,因为每个动态区域都作为其绑定数据集的侦听器。

Region Observes Data Set

图例 - 因为每个动态区域都作为其绑定数据集的侦听器

在数据集被改变的任何时候(loaded, updated, sorted, filtered, 等等),数据集将通知他的所有的侦听器,触发每个动态区域重新生成代码。

Data Set Notifies Region

图例 - 当数据集改变,每个动态区域都被通知,导致重新生成。

自定义属性被用于标示特殊的动态区域。这些自定义属性是附加了 XML 命名空间的 ,以便文档验证。所有使用Spry动态区域的文档都应该包含Spry命名空间。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
...

</html>

代码 - 包含Spry命名空间的HTML文档

返回

创建动态区域

动态区域被完全包含在一个单独的页面元素中。通过增加"spry:region" 属性,其值是用空格分开的数据集名称,告诉框架此元素中的内容是绑定了数据集的动态区域。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");

</script>
</head>
<body>
	<ul spry:region="dsPhotos">
		<li>{dsPhotos::path}</li>
	</ul>

</body>
</html>

代码 - 这个UL元素是一个绑定了dsPhotos 数据集的动态区域容器。

大多数元素都可以作为动态区域容器,但是也有些例外情况。下面的元素不能用于动态区域容器:

COL, COLGROUP, FRAMESET, HTML, IFRAME, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR

虽然上面的元素不能用于容器,但它们可以存在于动态区域容器内部。

返回

数据引用

在一个动态区域中,数据通过一下格式调用:

{<data set name>::<data set column>}

此格式用于标记在区域重新生成时数据插入的位置。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<ul spry:region="dsPhotos">
		<li>{dsPhotos::@path}</li>

	</ul>
</body>
</html>

代码 - {dsPhotos::@path} 是一个数据引用

如果一个区域只绑定一个数据集,在引用时可以省略数据集名称。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<ul spry:region="dsPhotos">
		<li>{@path}</li>

	</ul>
</body>
</html>

代码 - {@path}可以作为一个数据引用,因为区域只绑定了一个数据集。

当一个动态区域被重新生成,数据引用被当前数据行的数据替换。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<ul>
		<li>sun.jpg</li>

	</ul>
</body>
</html>

代码 - {@path} 被当前数据行的数据替换

每个数据集有一组内置的数据引用,当重新生成区域的时候很有用:

  • 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 - 这将视当前 ds_RowNumber 的值返回"even" 或 "odd",这在交替行背景颜色很有用。

像数据集列名一样,如果绑定了多个数据集,这些内建数据调用必须带有数据集名称的前缀。

返回

循环结构

动态区域现在支持2个循环结构。一个允许对于数据集的每一行循环一个元素和其内容(spry:repeat),另一个允许你循环元素的子元素 (spry:repeatchildren)。

标明一个要循环的元素,只需要给元素增加一个"spry:repeat"属性,其值是用于循环的数据集名称:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<div spry:region="dsPhotos">
		<ul>

			<li spry:repeat="dsPhotos">{@path}</li>
		</ul>
	</div>
</body>
</html>

代码 - 这个li将对于数据集的每一行进行循环

只循环子元素,只要使用"spry:repeatchildren" 属性:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>

</head>
<body>
	<div spry:region="dsPhotos">
		<ul spry:repeatchildren="dsPhotos">
			<li>{@path}</li>

		</ul>
	</div>
</body>
</html>

代码 - UL的子元素将对 dsPhotos 的每个数据行循环

上面的"spry:repeat" 和 "spry:repeatchildren" 例子功能上是相同的,但是"spry:repeatchildren"在同条件选择使用时更有用,下面说明。两个例子输出结果:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Dynamic Region Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<div>

		<ul>
			<li>sun.jpg</li>
			<li>tree.jpg</li>
			<li>surf.jpg</li>

		</ul>
	</div>
</body>
</html>

代码 - 区域重新生成的代码。

有时你可能不希望输出内容里不是所有的数据行。你可以在有"spry:repeat" 或 "spry:repeatchildren" 属性的元素再设置一个 "spry:test" 属性来限制输出的内容。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Dynamic Region Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<div spry:region="dsPhotos">

		<ul>
			<li spry:repeat="dsPhotos" spry:test="'{@path}'.search(/^s/) != -1;">{@path}</li>
		</ul>
	</div>

</body>
</html>

代码 - 结果只有第一个字母为‘s’的才被输出。

spry:test 属性的值可以是任何的 JavaScript非 零/false表达式。如果表达式返回一个非零值,内容则被输出。记住由于我们使用的是XHTML所以表达式中的特殊字符'&', '<' 或 '>' 等需要转为HTML实体。你也可以在表达式中使用数据引用,动态区域处理引擎会在计算表达式值之前替换实际的数据值。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<div>
		<ul>

			<li>sun.jpg</li>
			<li>surf.jpg</li>
		</ul>
	</div>
</body>

</html>

代码 - 只有开头字母为‘s’的路径才被输出。

返回

条件结构

动态区域支持两种条件结构。第一个是 "spry:if":

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<div spry:region="dsPhotos">
		<ul class="spry:repeat">

			<li spry:if="'{@path}'.search(/^s/) != -1;">{@path}</li>
		</ul>
	</div>
</body>
</html>

代码 - 只有开头字母为‘s’的路径才被输出。

做一个有条件的元素,为元素增加一个 "spry:if" 属性,属性值是任何的 JavaScript非 零/false表达式,如果表达式返回一个非零值,内容则被输出。

如果你需要一个 if/else 结构就使用 "spry:choose" :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Dynamic Region Example</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000", "/gallery/photos/photo");
</script>
</head>
<body>
	<div spry:region="dsPhotos">
		<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>
	</div>
</body>
</html>

代码 - 使用 spry:choose 输出不同的DIV。

"spry:choose" 提供等价一个 case 结构,或者一个 if/else if/else结构。创建一个 "spry:choose"结构需要在元素上加入一个 "spry:choose" 属性。下一步增加一个或多个有"spry:when"属性的子元素。 "spry:when" 的值可以是任何的 JavaScript非 零/false表达式。如果你需要一个默认情况,当所有的spry:when 情况都返回零值,加入一个"spry:default"属性。"spry:default"属性不需要值,但是XHTML 要求所有的属性都有值,所以我们使用其名子作为他的值。

动态区域引擎计算每个子元素 "spry:when" 的属性值。 只有在"spry:when"都返回零值的时候,"spry:default" 元素被最后计算。

返回

区域状态

Spry supports the notion of region states.Spry支持区域状态的概念。在任何时候,一个动态区域都有一个状态,可以是"loading","ready" 显示数据,或者加载数据错误的时候的 "error" 状态。一个元素可以有spry:state 属性,其值为"loading","error" 或 "ready",可以加在动态区域容器内对应各状态的元素上。这在显示“正在加载”等信息时很有用,或者通知用户“加载数据失败”。当区域状态改变的时候,相应的标记会被生成。

<div spry:region="dsEmployees">
	<div spry:state="loading">Loading employee data ...</div>
	<div spry:state="error">Failed to load employee data!</div>
	<ul spry:state="ready">
		<li spry:repeat="dsEmployees">{firstname} {lastname}</li>
	</ul>
</div>

代码 - 利用spry:state显示加载和错误信息。

需要注意的是没有 spry:state 属性的内容,或者不是一个具有 spry:state 属性元素的子元素,将一直在重生成的标记中存在。有spry:state 属性的元素其子元素则不能有spry:state 属性。这就是说有spry:state 属性的元素不能嵌套。

返回

区域侦听器通知

Spry 支持侦听器机制,允许开发者注册一个对象或函数接收当区域状态改变时接收通知。这个机制在下面的使用情况下是基本相同的:

  • 增加或删除区域侦听器使用全局函数 Spry.Data.Region.addObserver() 和 Spry.Data.Region.removeObserver。这和数据集是不同的,因为数据集侦听器调用的addObserver() 和removeObserver()是不在这个数据集对象上的。全局函数允许开发者在document.onload之前和生成区域的JavaScript对象创建之前注册侦听器。区域使用addObserver/removeObserver 函数原因是开发者想在JavaScript对象存在之前注册侦听器。
  • addObserver() 和 removeObserver() 需要一个ID来标识开发者想要监视的区域。因此,开发者要监视的区域必须有ID属性。

用对象作为区域侦听器

一个对象必须为每个通知定义一个函数,然后将自己注册为区域的侦听器。

<script>

...

// 创建一个侦听器对象并定义接收通知的函数。
myObserver = new Object;
myObserver.onPostUpdate = function(notifier, data)
{
	alert("onPostUpdate called for " + data.regionID);
};

...

// 调用 addObserver() 注册对象为侦听器
Spry.Data.Region.addObserver("employeeListRegion", myObserver);

...

// 你可以使用removeObserver()停止接收通知。
Spry.Data.Region.removeObserver("employeeListRegion", myObserver);

...

</script>

...

<ul id="employeeListRegion" spry:region="dsEmployees">

...

</ul>

代码 - 注册一个对象为动态区域监听器

The first argument for each notification method is the object that is sending the notification. 通知函数的第一个参数是发送通知的对象。因此对于区域侦听器,不是区域对象。这将在未来改变,但是同时第二个参数包含了一个触发通知的区域ID。

要停止接收通知,必须调用removeObserver()从监听器列表中移除对象。

函数作为区域侦听器

函数同样可以注册为监听器。对象侦听器和函数侦听器的主要区别是一个对象只接收定义了的类型的通知,然而函数侦听器将被每一种通知调用。

<script>

...

function myRegionCallback(notificationState, notifier, data)
{
	if (notificationType == "onPreUpdate")
		alert(regionID + " is starting an update!");
	else if (notificationType == "onPostUpdate")
		alert(regionID + " is done updating!");
}

...

// 调用 addObserver() 注册你的函数为侦听器
Spry.Data.Region.addObserver("employeeListRegion", MyRegionCallback);

...

// 你可以调用 removeObserver()删除侦听器
Spry.Data.Region.removeObserver("employeeListRegion", MyRegionCallback);

...

</script>

...

<ul id="employeeListRegion" spry:region="dsEmployees">

...

</ul>

代码 - 注册一个函数为动态区域侦听器。

函数监听器也通过addObserver注册。

当函数被调用,第一个参数是通知类型,这是一个通知名称的字符串。第二个参数是通知的发出者,这个例子中不是区域对象,未来可能改变。第三个参数是一个数据对象,具有一个regionID属性告诉我们那个区域触发了通知。

要停止接收通知,必须调用removeObserver()从监听器列表中移除对象。

下面是支持的通知类型表格:

区域通知类型
onLoadingData 一个或多个区域绑定的数据正在加载数据。
onPreUpdate 所有的区域绑定的数据成功加载数据。区域正准备重新生成标记。
onPostUpdate 区域已经重新生成标记,并插入到文档中。
onError 加载数据出现错误。

返回


隐藏数据调用

在一些浏览器中,通过慢速连接加载页面时会导致用户看到未处理的区域代码。

Spry动态区域在文档加载完成后自动移除 spry:region 和 spry:detailregion 属性。这样设计者就可以使用CSS定义一个规则在数据区域被处理前隐藏代码。只要Spry删除了这些属性,标记被重新生成后便可以显示出来处理后的结果了。知道我们使用 XML 命名空间属性的时候都工作的很好,不幸的是现在的浏览器CSS不支持 XML 命名空间,但是如果符合W3C的建议,下面的CSS将起作用:

<style>
@namespace spry url(http://ns.adobe.com/spry);
 	
*[spry|region], *[spry|detailregion]{
	visibility: hidden;
}
</style>

代码 - 这些CSS规则在支持CSS XML命名空间的浏览器可以正常工作。

因为没有浏览器支持CSS XML 命名空间,我们不得不实行"B计划"。动态区域处理代码自动删除有spry:region 或 spry:detailregion属性容器的样式名 "SpryHiddenRegion"。现在你只需要提供一个CSS规则 SpryHiddenRegion:

<style>
.SpryHiddenRegion {
	visibility: hidden;
}
</style>

...

<div spry:region="dsEmployees" class="SpryHiddenRegion">
...
</div>

代码 - 隐藏动态区域的CSS 样式SpryHiddenRegion。

替代的隐藏方式是,使用spry:content 属性。你可以使用 spry:content 属性替代一个数据引用。因此数据引用实际上是spry:content属性的值,这在页面加载视是不可见的。

<!-- Example of a normal region. -->
<div spry:region="dsEmployees">
	Hello my name is {firstname}.
</div>

<!-- Example of a region using spry:content. -->
<div spry:region="dsEmployees">
	Hello my name is <span spry:content="{firstname}"></span>.
</div>

代码 - 使用spry:content 属性隐藏代码

返回


主区/详细区域

当使用数据时,一些页面应用使用主/从显示方式。基本的概念是页面上有一个主区域,它驱动另一个区域的变化,即详细区域。通常,主区域显示概要数据,详细区域显示当前纪录的详细信息。

Master/Detail

图例 - 左边的表格是主区域,右边则是详细区域。

Master/Detail Changed
图例 - 当用户在主区域中选择了不同的对象,详细区域也会更新。

Spry框架使得在2个以上的区域建立主从关系变得很容易:

  • 数据集以当前行的概念维护。在当前行改变时,数据集给所有监听器发送通知。
  • 动态区域注册自己为其绑定的数据集的监听器,因此它们可以在数据改变时自动更新。
  • XML数据集的 URL 和 XPath 构造函数的参数可以包含其他数据集的数据引用。

你可能注意到,数据集在上面提到的情况很普遍,因此建立主从应用技术的核心是一个或多个数据集的使用。

让我们看几个例子来演示如何利用这些概念:

样例 1: 在主要和详细区域都使用同一数据集的时候使用 "spry:detailregion"

这个例子中主要和详细区域都基于一个数据集。查看实际例子演示。

主区域是由一个选单列表组成,用来显示员工用户名。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Master/Detail Same Data Set</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee");
</script>
</head>
<body>
<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>
</body>
</html>

代码 - 主区域包含一个选择列表。

选单项目由dsEmployees 数据集生成,值是当前关联行的ds_RowID,显示的值是行的 "username" 字段。一组 "spry:if" 选项可以为第一个项目增加选定属性 "selected"。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Master/Detail Same Data Set</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">

var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee");
</script>
</head>
<body>
<span>
<select onchange="dsEmployees.setCurrentRow(this.value)">
	<option value="0" selected="selected">esmith</option>

	<option value="1">njohnson</option>
	<option value="2">swilliams</option>
	<option value="3">jjones</option>

	<option value="4">jbrown</option>
</select>
</span>

<span>123456 - Edward Smith - (415) 333-0235 </span>
</body>

</html>

代码 - 在主区域生成后的代码。

详细区域是一个显示选定员工的员工ID,last name,电话号码的span。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Master/Detail Same Data Set</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee");
</script>

</head>
<body>
<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>

</body>
</html>

代码 - 详细区域显示选择列表中选定的员工的详细信息。

你会注意到详细区域使用的是"spry:detailregion" 属性而不是"spry:region" 属性。"spry:region" 和 "spry:detailregion" 是类似的。除了有"spry:detailregion"属性的动态区域将在收到"CurrentRowChanged" 通知的时候更新自己的代码。

Master/Detail spry:detailregion

图例 - 有"spry:detailregion" 属性的区域监听 CurrentRowChanged 通知。

当用户改变选择的员工时,选框的onchange 处理器被触发。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Master/Detail Same Data Set</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee");
</script>

</head>
<body>
<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>

</body>
</html>

代码 - 当选择列表改变的时候,dsEmployees数据集的当前行被改变。

onchange 处理器只是简单的调用dsEmployees数据集的setCurrentRow() 方法,并传递向关联的数据行的ID。CurrentRowChanged通知导致详细区域重新生成。

Master/Detail spry:detailregion notification

图例 - 主区域setCurrentRow触发CurrentRowChanged 通知到详细区域。

样例 2: 主区域和详细区域使用两个不同的数据集

这个例子中我们有一个用户显示州名的数据集,和另一个显示给定州的城市名的数据集。因为城市列表很长,第二个数据集的数据只有在州名称改变时请求。 你可以查看样例二。

由于州列表很长,所以这个例子中使用select选单显示信息。当用户选择了州,城市选单将自动更新对应州的城市。

我们开始创建需要的两个数据集。一个提供州 (dsStates) 另一个提城市 (dsCities)。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>States Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
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");
</script>

</head>
<body>
</body>
</html>

代码 - dsCities 的 URL 基于 dsStates 数据集

如果你观察dsCities的URL,你会发现它是一个数据引用"{dsStates::url}" 。 URL 和 XPath 参数 允许包含另一个数据集的数据引用,只要不创建循环的调用就可以,就是说你不能有一个基于数据集‘A’的数据集‘B’,而这个数据集‘B’又基于数据集‘A’。同样,你也不可以有一个数据集‘B’基于‘A’,‘A’基于‘C’,‘C’又基于‘B’。

如果数据集的URL或XPath是数据引用,数据集将把自己注册为用到的数据集的监听器。这将允许数据集在其以来的数据集发生DataChanged 或 CurrentRowChanged 通知的时候更新自己的数据。数据参考将在数据集调用URL或使用XPath解析XML数据之前转换为真是数据。

在本例中应该注意, URL "data_set_overview/samples/data/states/{dsStates::url}" 的结果是一个特定的样例XML文件,但是如果是实际的应用程序URL可能类似"/webapp/cities.php?stateid={dsStates::@id}".

现在我们要建立数据集,建立我们的主区域和从区域。主区域包含一个select表单元件用来显示 dsStates数据集中的州名。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>States Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
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");

</script>
</head>
<body>
<form name="selectForm">
	State:
	<span spry:region="dsStates" id="stateSelector">

		<select spry:repeatchildren="dsStates" name="stateSelect">
			<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>
</form>

</body>
</html>

代码 - 主区域显示一个州列表选单。

详细区域将包含一个select表单元件从dsCities显示当前州的城市列表。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>States Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
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");

</script>
</head>
<body>
<form name="selectForm">
	State:
	<span spry:region="dsStates" id="stateSelector">

		<select spry:repeatchildren="dsStates" name="stateSelect">
			<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>

</body>
</html>

代码 - 主区域显示一个指定州的城市列表选单。

At this point, 到这里,我们有了下面的数据集同动态区域的关系:

Master/Detail Observer Relationships

图例 - 数据集同动态区域之间的监听器关系。

为了使"City"选单在用户选择了"State"后自动变化,我们要给"State"选单增加一个onchange处理器。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>States Example</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
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");
</script>
</head>
<body>

<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>
</body>
</html>

代码 - 给"State"选单增加一个onchange处理器

这个处理器禁用City选择框,然后设置dsStates数据集中的当前行。这将导致CurrentRowChanged通知触发,使dsCities数据集重新加载数据。当dsCities数据集加载数据,触发DataChanged通知,使得详细区域重新生成,显示州数据集dsState当前行对应的城市列表。

Master/Detail URL/XPath data reference auto update

图例 - 改变 'A'数据集的当前行引起链式反映使详细区域更新。

返回


行为属性

行为属性可以用于动态区域中的元素。现在只有两种行为属性:

  • spry:hover - 当鼠标指针移动到元素上时,给此元素增加样式名,指针移出的时候移除样式名。
  • spry:select - 当鼠标点击元素时,给元素增加样式名。

spry:hover

"spry:hover" 属性的值应该是鼠标移上元素时应用的样式名。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Behavior Attributes Example</title>
<style>
.myHoverClass {
	background-color: yellow;
}

</style>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script> <script type="text/javascript"> var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee"); </script> </head> <body> <div spry:region="dsEmployees"> <ul> <li spry:repeat="dsEmployees" spry:hover="myHoverClass">{username}</li> </ul> </div> </body> </html>

代码 - 只要鼠标一移上LI元素,"myHoverClass" 样式名将被加到li元素的属性上。在鼠标移除的时候自动删除样式名。

spry:select

"spry:select" 属性的值应该是鼠标点击元素时应用的样式名。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Behavior Attributes Example</title>
<style>
.myHoverClass {
	background-color: yellow;
}

.mySelectClass {
	color: white;
	background-color: black;
}
</style>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee");
</script>
</head>
<body>
<div spry:region="dsEmployees">

	<ul>
		<li spry:repeat="dsEmployees" spry:hover="myHoverClass" spry:select="mySelectClass">{username}</li>
	</ul>

</div>
</body>
</html>

代码 - 只要鼠标一点击LI元素,"mySelectClass" 样式名将被加到li元素的属性上。

如果页面一个有"spry:select"属性的元素先前已经被选中,那么在失去选择时 "spry:select"属性使用的样式名将被自动删除。

你可以 "spry:selectgroup"属性和"spry:select"属性一同使用,这样可以在一个页面里实现多个选择区。查看 RSS 阅读器 样例,这是一个此框架实现的多选择示例。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Behavior Attributes Example</title>

<style>
.myHoverClass {
	background-color: yellow;
}
.mySelectClass {
	color: white;
	background-color: black;
}
.myOtherSelectClass {
	color: white;
	background-color: black;
}
</style><script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script> <script type="text/javascript"> var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "/employees/employee"); </script> </head> <body> <div spry:region="dsEmployees"> <ul> <li spry:repeat="dsEmployees" spry:hover="myHoverClass" spry:select="mySelectClass" spry:selectgroup="username">{username}</li> </ul> <ul> <li spry:repeat="dsEmployees" spry:hover="myHoverClass" spry:select="myOtherSelectClass" spry:selectgroup="firstname">{firstname}</li> </ul> </div> </body> </html>

代码 - 使用 spry:selectgroup 属性将元素分组。

"spry:selectgroup"属性的值是一个独立名称,这是为了使 "spry:selectgroup"属性名相同的一组元素中,选择时互斥,当一个元素被选中时,其他已经选中的元素将被取消选定,而使用不同"spry:selectgroup"值的一组元素则不受影响。

返回


增强与改进和数据可访问性

增强与改进是为了是文档支持最基本的浏览器功能的同时增强呈现效果而使用一些技术,主要使用的技术例如CSS,JavaScript, Flash, Java, SVG,等等。主旨是使用这些技术的页面将在流行的浏览器中提供增强的用户体验,但是在没有这些技术的时候,数据还是可以访问,页面可以正常使用。

然而到目前,这个文档中所有的Spry样例都使用JavaScript加载XML数据然后生成数据区域,以上面提到的增强与改进的方式使用Spry基于Hijax方法是可能的。Hijax方法说明了使用JavaScript不影响使用的情况下给页面中类似链接的元素附加事件处理器来捕捉用户的操作,比如点击等一些操作。它还说明了使用服务器异步生成的代码片断替换文档现有部分的能力,而不用重新加载整个页面。

一个以此方法使用Spry的例子,你可以从一个只有静态数据和链接的页面开始:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Hijax Demo - Notes 1</title>

</head>

<body>
<a href="notes1.html">Note 1</a>
<a href="notes2.html">Note 2</a>
<a href="notes3.html">Note 3</a>

<div>
	<p>This is some <b>static content</b> for note 1.</p>
</div>
</body>
</html>

代码 - 传统的静态页面

使用Spry增强和改进这个页面,你不用在点击链接的时候加载整个新页面,你首先要保证每个链接指向的代码片断都能够以XML方式访问。下面是一种将静态数据外置的方法:

<?xml version="1.0" encoding="iso-8859-1"?>
<notes>
	<note><![CDATA[<p>This is some <b>dynamic content</b> for note 1.</p>]]></note>

	<note><![CDATA[<p>This is some <b>dynamic content</b> for note 2.</p>]]></note>
	<note><![CDATA[<p>This is some <b>dynamic content</b> for note 3.</p>]]></note>

</notes>

你可以在页面使用Spry:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Hijax Demo - Notes 1</title>
<script language="JavaScript" type="text/javascript" src="includes/xpath.js"></script>

<script language="JavaScript" type="text/javascript" src="includes/SpryData.js"></script>
<script language="JavaScript" type="text/javascript">
<!--
var dsNotes = new Spry.Data.XMLDataSet('data/notes.xml', "/notes/note");
-->

</script>
</head>

<body>
<a href="note1.html" onclick="dsNotes.setCurrentRowNumber(0); return false;">Note 1</a>
<a href="note2.html" onclick="dsNotes.setCurrentRowNumber(1); return false;">Note 2</a>

<a href="note3.html" onclick="dsNotes.setCurrentRowNumber(2); return false;">Note 3</a>
<div spry:detailregion="dsNotes" spry:content="{note}">
	<p>This is some <b>static content</b> for note 1.</p>

</div>
</body>
</html>

代码 - 增加了Spry的传统页面。

上面的Spry代码很熟悉,但是你要注意在spry:detailregion DIV上有一个"spry:content"属性,这个属性告诉Spry的动态区域处理代码替换静态数据为绑定这个区域的动态数据集中的数据。

因此如果浏览器不支持JavaScript,他将会回到开始的静态页面和传统的链接导航。如果JavaScript支持开启,我们的数据集将从XML文件中加载数据填充到动态区域中,点击链接将从数据集中更新数据。

对于上面例子的一个注释。Hijax建议给链接增加不影响正常功能的事件处理器。上面的例子有意使用了onclick属性以快速描述附加的JS事件处理器。


 

 

http://www.sprycn.com/ 转自