内容


使用 Dojo 的 Ajax 应用开发进阶教程,第 9 部分

Dojo 扩展库:丰富的组件资源仓库

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 使用 Dojo 的 Ajax 应用开发进阶教程,第 9 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:使用 Dojo 的 Ajax 应用开发进阶教程,第 9 部分

敬请期待该系列的后续内容。

现在的 Ajax 应用开发一般都要求比较短的上市时间(Time to market),也就是说一个应用从完成构思到推出来给用户使用的时间要尽可能的短。这主要是为了尽早的获得用户的反馈,从而对应用进行相应的调整。一般来说应用都会包含一些通用的功能和用户界面组件。如果从头开发这些功能和组件的话,无疑会增加开发时间,质量也比较难以得到保证。如果能够复用已有的经过良好测试的组件的话,可以极大的减少开发时间,降低开发成本。

Dojo 扩展库是 Dojo 提供的一个非常丰富的组件仓库,里面提供了各式各样功能各异的组件。这些组件都提供了比较好的定制能力,经过一些简单的定制就可以满足不同的需求。Dojo 扩展库中的组件在经过测试和使用之后,有可能会成为 Dojo 核心库和 Dijit 库的一部分。

在开发使用 Dojo 的 Ajax 应用的时候,了解和使用 Dojo 扩展库中的组件可以帮助更快的进行开发。本文会介绍一些 Dojo 扩展库中的常用组件。所有的组件介绍都基于最新的 Dojo 1.5 版本。在 Dojo 扩展库的组件中,有一些是比较常见并且相关的文档比较多的。对于这些组件,在本文中并没有介绍,读者可以参考相关的其它文档。这些组件包括:dojox.chartingdojox.cometddojox.editordojox.gfxdojox.grid等。首先介绍 dojox.lang模块。

dojox.lang

dojox.lang模块提供了对异步操作的处理、面向方面编程(AOP)的支持以及函数式编程的支持等。

异步操作的处理

Dojo 基本库中提供了 dojo.Deferred对象来对异步操作进行抽象,而 dojo.DeferredList则提供了对一组 dojo.Deferred对象的简单的管理功能。dojox.lang.async模块在这基础上提供了更加丰富的基于 dojo.Deferred的异步操作的支持。

dojox.lang.async.seq(fs)用来顺序执行一组 JavaScript 方法。参数 fs是一个包含多个 Javascript 方法的数组,也可以直接把每个方法作为单独的参数直接传入。这些 JavaScript 方法本身也可以返回 dojo.Deferred对象,从而形成异步操作级联调用的效果。在序列中的后一个 JavaScript 方法会等待前一个调用完成之后才被调用。通过调用 dojox.lang.async.seq()方法返回的是另外一个 JavaScript 方法,需要再次调用此方法才会启动执行过程。而这个方法也接受一个可选的参数作为调用时的初始值。dojox.lang.async.seq()方法的返回值是一个 dojo.Deferred对象,可以用来在所有的 JavaScript 方法都执行完成之后,再执行特定的代码。

dojox.lang.async.par(fs)用来并发执行一组 JavaScript 方法,会等待所有 JavaScript 方法都执行完成。dojox.lang.async.any(fs)用来并发执行一组 JavaScript 方法,只要有一个方法返回结果,就终止其它方法的执行。dojox.lang.async.select(cond, fs)用来根据某个条件选择执行特定的 JavaScript 方法。参数 cond表示某个条件,它应该返回一个序号。根据这个序号从由参数 fs指定的 JavaScript 方法中选择一个来执行。dojox.lang.async.ifThen(cond, ifTrue, ifFalse)的作用与 dojox.lang.async.select()类似,不同的是 cond表示的 JavaScript 方法应该返回真值或假值,根据这个结果来选择执行 ifTrue或是 ifFalse表示的 JavaScript 方法。dojox.lang.async.loop(cond, body)用来循环执行某个 JavaScript 方法。参数 cond指定的 JavaScript 方法给出了循环继续执行的条件,而参数 body指定的 JavaScript 方法则是循环体。代码清单 1中给出了一个使用 dojox.lang.async的示例。

清单 1. dojox.lang.async 示例
 var async = dojox.lang.async; 
 var wait = async.timeout.from; 
 function waitAndLog(ms) { 
    return function() { 
        var d = wait(ms)(); 
        d.addCallback(function() { 
            console.log("Finished timeout - " + ms); 
        }); 
        return d; 
    };  
 } 
 var fs = [waitAndLog(100), waitAndLog(200), waitAndLog(300)]; 
 async.seq(fs)().addCallback(function() { 
    console.log("seq done!"); 
 }); 
 async.par(fs)().addCallback(function() { 
    console.log("par done"); 
 }); 
 async.any(fs)().addCallback(function() { 
    console.log("any done"); 
 }); 
 async.select(function() { 
    return 1; 
 }, fs)(); 
 async.ifThen(function() { 
    return 1; 
 }, waitAndLog(100), waitAndLog(200))(); 
 var count = 3; 
 async.loop(function() { 
    console.log("loop - " + count); 
    return --count; 
 }, waitAndLog(100))();

代码清单 1所示,waitAndLog()方法通过 setTimeout()来模拟异步操作。示例所用的三个异步操作分别延迟 100 毫秒、200 毫秒和 300 毫秒。通过控制台输出的日志就可以看到 seq()par()any()等方法执行完成的时间。

面向方面编程(AOP)的支持

面向方面编程(Aspect-oriented programming,AOP)的思想适合于处理应用中的横切需求,如用户认证、记录日志和异常处理等。dojox.lang.aspect模块提供了在 JavaScript 中的面向方面编程的支持。

dojox.lang.aspect只支持方法这一种连接点(joint point),支持的增强(advice)有前增强(before advice)、后增强(after advice)和环绕增强(around advice)等,而后增强又有正常返回时和出现异常时的增强。增强中定义的方法在满足指定条件的时候会被执行。通过 dojox.lang.aspect.advise(obj, method, advice)方法来添加增强。该方法的第一个参数 obj表示要增强的方法所在的对象;第二个参数 method可以是要增强的方法的名字,或是通过正则表达式来指定一组方法,如所有以 get开头的方法;最后一个参数 advice表示要添加的增强。该方法的返回值可以传递给 dojox.lang.aspect.unadvise()方法来删除所添加的增强。代码清单 2中给出了 dojox.lang.aspect的使用示例。

清单 2. dojox.lang.aspect 示例
 var User = { 
    name : "Alex", 
    email : "alex@example.org", 
    getName : function() { 
        return this.name; 
    }, 
    setEmail : function(email) { 
        this.email = email; 
    } 
 }; 

 dojox.lang.aspect.advise(User, "getName", { 
    afterReturning : function(value) { 
        console.log(value); 
    } 
 }); 
 dojox.lang.aspect.advise(User, "setEmail", { 
    around : function(email) { 
        if (!email) { 
            console.log("email is null, ignore."); 
            return; 
        } 
        return dojox.lang.aspect.proceed.apply(null, arguments); 
    } 
 }); 

 User.getName(); // 输出 Alex 
 User.setEmail(); // 输出提示信息:email is null, ignore. 
 console.log(User.email); // 输出 alex@example.org 
 User.setEmail("bob@example.org"); 
 console.log(User.email); // 输出 bob@example.org

代码清单 2所示,User对象中包含了 getName()setEmail()两个方法。第一个 dojox.lang.aspect.advise()方法添加了 afterReturning增强,可以获得 getName()方法正常执行之后的返回值,此处只是简单的输出该返回值。第二个 dojox.lang.aspect.advise()方法添加了 around增强,可以改变原来的 setEmail()方法的执行流程。当传入的参数 email为空的时候,就直接返回;否则的话,通过 dojox.lang.aspect.proceed()方法就可以执行原来的方法。在这里还可以对原来方法的返回值进行修改。

在介绍完 dojox.lang模块之后,下面介绍 dojox.html模块。

dojox.html

dojox.html模块提供了对 HTML 和 CSS 样式的附加支持,是对 dojo.style()dojo.addClass()dojo.removeClass()dojo.toggleClass()等方法的重要补充。

动态 CSS 样式

在使用 Dojo 的 Ajax 应用中,一般是通过 dojo.style()来直接修改 CSS 样式或是使用 dojo.addClass()来为元素添加新的 CSS 类名。不过这要求 CSS 样式的声明是预先写好的。通过 dojox.html.insertCssRule(selector, declaration, styleSheetName)方法可以动态添加 CSS 样式规则。该方法的参数 selector表示的是 CSS 样式规则的选择器,declaration表示的是样式声明,styleSheetName表示的是将规则添加到的样式表的名称。如 dojox.html.insertCssRule("#myDiv span", "font-size : 1.2em;")就添加了一条新的样式规则。通过 dojox.html.insertCssRule()添加的样式规则可以通过 dojox.html.removeCssRule()方法来删除。两个方法的参数是相同的。

另外一些方法可以用来对当前页面上的样式表进行操作。这些方法有:

  • dojox.html.getStyleSheets():返回页面上所引用的所有样式表。
  • dojox.html.getToggledStyleSheets():返回页面上所有可以被切换的样式表,包括那些包含了 titlehref属性的样式表。
  • dojox.html.getStyleSheet(styleSheetName):返回页面上的某个样式表。参数 styleSheetName表示样式表的 titlehref属性。
  • dojox.html.getDynamicStyleSheet(styleSheetName):创建或获取用来添加动态 CSS 样式规则的样式表。参数 styleSheetName表示的是样式表的名称。
  • dojox.html.enableStyleSheet(styleSheetName):用来启用名称为 styleSheetName的样式表。
  • dojox.html.disableStyleSheet(styleSheetName):用来禁用名称为 styleSheetName的样式表。
  • dojox.html.activeStyleSheet(title):用来启用 title属性为参数 title值的样式表,同时禁用其它的可以被切换的样式表。

利用 dojox.html.activeStyleSheet(title)方法可以非常容易的实现切换主题的功能。只需要为每个主题的样式表定义不同的 title属性,当用户选择切换主题的时候,调用 dojox.html.activeStyleSheet()来启用用户选择的主题即可。

字体大小

在 Ajax 应用中有可能需要知道 CSS 中的字体声明所代表的真实字体大小。比如 1em所表示的字体是多少像素的。dojox.html.metrics.getFontMeasurements()方法提供了这样的功能,可以用来获得 CSS 样式声明中 1em1ex100%12pt16pxxx-smallx-smallsmallmediumlargex-largexx-large所表示的字体的像素值。

dojox.html.metrics.getTextBox(text, style, className)可以用来度量一段文本所占据的空间大小。如果用来显示一段文本的区域的大小是固定的,当文本过长而无法完整显示的时候,就需要截断文本。dojox.html.metrics.getTextBox()的返回值是一个 JavaScript 对象,其中的 hw分别表示文本占据空间的高度和宽度。

在介绍完 dojox.html模块之后,下面介绍 Dojo 扩展库中提供的集合类。

集合类

JavaScript 中的数组提供了比较多的对其内部的元素进行处理的方法,不过使用起来比较不直观。开发人员可能需要一些抽象层次更高的数据结构。dojox.collections模块就提供了这些数据结构,包括栈、集合、词典和队列等。

dojox.collections.ArrayList可以看做是数组的一个简单封装。在原有的数组操作的方法之上,提供了一些更加直观的方法,包括 add()insert()remove()sort()indexOf()等。

dojox.collections.Set则提供了与集合操作相关的方法。dojox.collections.Set.union(setA, setB)用来求两个集合的并集。dojox.collections.Set.intersection(setA, setB)用来求两个集合的交集。dojox.collections.Set.difference(setA, setB)用来求两个集合的差集,也就是说在集合 setA中,但是不在集合 setB中的元素。dojox.collections.Set.isSubSet(setA, setB)用来判断 setB是否为 setA的子集。dojox.collections.Set.isSuperSet(setA, setB)用来判断 setB是否为 setA的超集。

dojox.collections.Stack是一个栈的实现。它所提供的方法有:clear()用来清空整个栈;clone()用来复制整个栈;contains(obj)用来判断栈中是否包含元素 objcopyTo(array, index)用来把栈中的元素复制到数组 array中序号为 index的位置上;peek()用来查看当前栈顶的元素;pop()用来弹出栈顶元素;push(obj)用来将元素 obj压入栈中;toArray()把栈转换成一个数组。

dojox.collections.Dictionary是一个哈希表的实现。表中包含的是名值对。它所提供的方法除了 add(key, value)clear()clone()containsremove()等比较直观的外,还有 containsValue(value)用来判断词典中是否包含某个值 valuegetKeyList()用来获取词典中包含的键的列表,以及 getValueList()用来获取词典中包含的值的列表。

在介绍完集合类之后,下面介绍与 JSON 相关的内容。

JSON

JSON 查询

使用 Dojo 的开发人员对于 dojo.query()方法肯定不陌生,它可以用来查询当前文档树中的元素。dojox.json.query(query, obj)的作用与 dojo.query()类似,只不过查询的对象是 JavaScript 对象。该方法的参数 query是满足一定语法格式的查询表达式,而 obj则是待查询的 JavaScript 对象。dojox.json.query()所支持的查询语法如 表 1所示。

表 1. dojox.json.query 语法说明
操作符说明
.property返回对象中属性 property的值。
[expression]求出表达式 expression的值,根据其结果返回对象中的属性。
[?expression]对数组进行过滤操作,仅返回其中满足表达式 expression的条目。
[^?expression][?expression]类似,对数组进行过滤操作,不过会删除掉结果中的重复条目。
[\expression],[/expression]对数组中的条目根据表达式 expression的值来进行排序,\表示降序排列,/表示升序排列。多个表达式可以通过逗号串联起来表示组合排序。
[=expression]对数组中的条目进行映射操作,转换成一个新的数组。其用法相当于 dojo.map()方法,对数组中的每个条目执行表达式 expression,所得到的结果存放在新的数组中。
[start:end:step]求数组的子数组。startendstep分别表示子数组的起始位置、结束位置和间隔的步长。
[expr, expr][]内是一组逗号分隔的表达式,返回的结果是这些表达式执行结果的并集。
..property对当前对象进行递归搜索,返回一个包含所有名为 property的属性的值的数组。
..[?expression]对当前对象进行递归过滤操作。
expr = expr在进行过滤操作的时候可以使用 =来作为条件。当与字符串进行比较的时候,还可以使用 *?等通配符。
expr ~ expr表示不区分大小写的字符串比较。
$@$表示查询的根对象,而 @则表示查询的当前对象。$1$2$3表示查询时传入的额外参数。

代码清单 3中给出了一个示例来说明 dojox.json.query()的用法。

清单 3. dojox.json.query() 示例
 var obj = [{name : "Alex", age : 20, address : {city : "Beijing"}}, 
    {name : "Bob", age : 34, address : {city : "Shanghai"}}, 
    {name : "Dale", age : 28, address : {city : "Beijing"}}]; 

 dojox.json.query("..name", obj); 
 dojox.json.query("..[?age > 30]", obj); 
 dojox.json.query("..[?age > 30][=name]", obj); 

 var year = new Date().getFullYear(); 
 dojox.json.query("..[?age > 30][=$1 - age]", obj, year); 

 dojox.json.query("[/age][=name]", obj);

代码清单 3所示,第一个查询在对象 obj中递归搜索名为 name的属性,把结果作为数组返回。第二个查询搜索 age属性的值大于 30的对象。第三个查询在第二个的基础上,通过映射操作,只返回对象的 name属性。第四个查询首先获得当前的年份,然后通过映射操作,就可以返回年龄大于 30的人的出生年份。最后一个查询首先按照属性 age进行升序排列,然后输出属性 name的值。

语法验证

与 XML 格式相比,JSON 对数据的格式并没有严格的要求。在某些情况下,要求数据满足一定的格式要求是很重要的。比如应用如果允许用户通过编写 JSON 格式数据的方式来进行配置的话,服务器端需要对用户提交的 JSON 数据进行验证,以保证符合一定的规则要求。dojox.json.schema模块可以用来对 JSON 格式的数据进行验证,以确保数据满足一定的格式。

dojox.json.schema模块的重要方法是 dojox.json.schema.validate(instance, schema),其参数 instance表示的是待验证的 JavaScript 对象,而 schema表示的是数据应该要满足的格式声明的 JavaScript 对象。参数 schema所支持的语法格式描述非常丰富,包括数据类型的检查,验证必需的字段以及对不同类型的数据提供的额外检查,如数字的范围,字符串长度等。代码清单 4中给出了一个 dojox.json.schema的示例。

清单 4. dojox.json.schema.validate() 方法示例
 var schema = { 
    type : "object", 
    properties : { 
        name : {type : "string", optional : false}, 
        age : {type : "number", minimum : 0, maximum : 200} 
    } 
 }; 

 var obj1 = {name : "Alex", age : 30}; 
 var obj2 = {email : "test@example.org"}; 
 var obj3 = {name : "Bob", age : "a string"}; 

 dojox.json.schema.validate(obj1, schema); // 合法
 dojox.json.schema.validate(obj2, schema); // 非法,缺少属性 name 
 dojox.json.schema.validate(obj3, schema); // 非法,属性 age 数据类型不正确

在介绍完 JSON 的支持之后,下面介绍 I/O 请求相关的内容。

I/O

Dojo 提供了很多种不同的 I/O 传输方式的支持,包括 Dojo 基本库中的 XMLHttpRequest 和 Dojo 核心库中的 iframe 和 <script> 元素的支持。Dojo 扩展库中又额外提供了几种 I/O 传输方式的支持。

window.name

window.name是一种能够安全进行跨域访问的 I/O 传输方式。它利用的是 window.name这个属性来传递数据。它的工作方式是在一个 iframe 中加载一个其它域上的 HTML 文件。这个 HTML 文件通过 JavaScript 来设置 window.name属性为要传递的数据。iframe 加载完成之后,父页面就可以通过获取 window.name属性的值来得到数据。所传输的数据格式只能是字符串。

使用 Dojo 扩展库中的 window.name传输方式非常简单,只需要调用 dojox.io.windowName.send(method, args)方法即可。该方法的第一个参数 method表示所使用的传输方法,可以是 GETPOST;第二个参数 args是标准的 dojo.xhr方法使用的参数对象。使用 window.name进行传输的时候,服务器端返回的 HTML 文档的格式如 代码清单 5所示。

清单 5. window.name 传输方式服务端返回的 HTML 文档
 <html> 
    <script type="text/javascript"> 
        window.name='{"username":"Alex", "email" : "alex@example.org"}'; 
    </script> 
 </html>

代码清单 5所示,传输 JSON 或是 XML 格式的数据也是可行的。dojox.io.windowName.send()方法在发送请求的时候会添加查询参数 windowname=true。服务器端可以根据此参数来返回正确的结果。

dojox.io.scriptFrame

dojox.io.scriptFrame扩展自 Dojo 核心库中的 dojo.io.scriptdojo.io.script允许通过参数 frameDoc来指定把获取数据用的 <script>元素添加到某个子 iframe 中。不过使用 dojo.io.script的时候,要求开发人员自己来管理 iframe。dojox.io.scriptFrame简化了这一操作。当参数 frameDoc的值是字符串的时候,dojox.io.scriptFrame会负责创建所需的 iframe。

在介绍完 I/O 传输相关的内容之后,下面介绍数据仓库的实现。

数据仓库

Dojo 扩展库中提供了非常多的数据仓库的实现,可以满足不同数据源的要求。利用这些数据仓库的实现,可以很容易的把各种异构的数据源,统一成 dojo.dataAPI 规范的格式,可以用一个统一的接口来访问和操作。Dojo 扩展库中提供的数据仓库大概可以分成下面几类:

  • 对通用数据结构的封装。包括 HTML 表格、名值对、CSV 和 XML 等。
  • 对服务器端接口的封装。
  • 对常见 Web 服务的封装。包括 Google、Flickr 和 Wikipedia 等。

下面介绍几个比较重要和常用的数据仓库实现。

dojox.data.XmlStore

在 Ajax 应用中经常会需要处理 XML 文档,如 ATOM/RSS 订阅源或是服务器端返回的特定格式的 XML 文档等。在浏览器端用 JavaScript 处理 XML 文档并不是一件容易的事情,需要考虑一些浏览器兼容性的问题,而且只能用 DOM API 去查询和操作文档。dojox.data.XmlStore对 XML 文档提供了一层封装,允许开发人员用 dojo.data的 API 去访问和操作文档。

dojox.data.XmlStore的构造方法接受一个 JavaScript 对象作为参数。该 JavaScript 对象的属性 url表示要加载的 XML 文档的 URL;rootItem表示的是数据仓库中条目所对应的 XML 文档中的元素的名称。如对 ATOM 订阅源来说,rootItem属性的值就可以是 entry。不指定该属性的时候,默认使用的是 XML 文档的根元素;attributeMap用来指明一种条目的属性名称和 XML 元素属性的映射关系。比如在 XML 元素中原来的属性名称是 dataUrl,意义不是非常明确。可以通过 attributeMap来指定一个新的名称,如 userDataUrl

前面提到,dojox.data.XmlStore中的条目对应的是由 rootItem属性给出的指定名字的 XML 元素。当使用 getValue()方法来获取条目中属性的值的时候,返回的值都来源于该条目对应的 XML 元素,具体来说分下面几种情况:

  • tagName:返回 XML 元素的名称。
  • childNodes:返回 XML 元素的子元素。
  • text():返回 XML 元素的文本内容。
  • 如果属性名称出现在 attributeMap中,则返回对应的 XML 元素的属性的值。如果属性名称以“@”开头,则返回 XML 元素的属性的值。
  • 其余情况下,返回 XML 元素的名称为该属性的第一个子元素。

dojox.data.QueryReadStore

在 Ajax 应用中经常使用的一种架构是服务器端暴露以 JSON 作为表示格式的 REST 接口,浏览器端使用 XMLHttpRequest 来异步获取这些数据。服务器端会提供分页、排序还有过滤等能力;而浏览器端代码则需要处理与服务器端的交互过程。dojox.data.QueryReadStore提供了一种简单的方式把服务器端暴露的 REST 接口抽象成 Dojo 的数据仓库。dojox.data.QueryReadStore也支持浏览器端的分页和排序。

其它数据仓库实现

除了上面介绍的数据仓库之外,还有其它一些数据仓库可以满足不同的需求,具体如下:

  • dojox.data.AtomReadStore:提供对 ATOM 订阅源的支持。
  • dojox.data.CsvStore:提供对 CSS 数据的支持。
  • dojox.data.HtmlStore:提供对 HTML 表格元素 <table> 的支持。
  • dojox.data.KeyValueStore:提供对名值对的支持。
  • dojox.data.OpenSearchStore:提供对符合 OpenSearch 规范的搜索结果的支持。
  • dojox.data.OpmlStore:提供对 OPML 文件的支持。

在介绍完数据仓库的实现之后,下面介绍浏览器端的存储机制。

浏览器端存储

在 Ajax 应用中,浏览器端也需要承担一部分与应用逻辑相关的职责,这其中就涉及到存储相关的内容。浏览器默认只可以使用 cookie 作为存储方式,但是 cookie 所能存储的数据内容很少,一般不能超过 4K。这对于一些 Ajax 应用来说是不够的,尤其是那些需要支持用户离线运行的应用。更多的存储空间则需要浏览器本身或是附加插件的支持,如 Google Gears 和 Flash。不过这些附加插件所提供的 API 存在一些差异,应用开发人员需要检测当前浏览器所支持的插件类型来使用对应的 API。dojox.storage模块为这些不同的浏览器端存储方式提供了一层抽象,开发人员使用统一的 API 就可以完成数据的存储操作。

dojox.storage模块提供了一个存储服务提供者接口 dojox.storage.Provider,各种不同的存储实现机制都实现此接口。开发人员使用此接口来进行数据存储。另外还提供 dojox.storage.manager用来管理这些实现机制。dojox.storage.Provider接口提供了一系列用来存储数据的方法,具体如 表 2所示。

表 2. dojox.storage.Provider 方法说明
方法说明
put(key, value, resultsHandler, namespace)存储一个键值对。keyvalue分别表示键和值,键必须是字符串,而值可以是任何 JavaScript 对象。resultsHandler是一个回调方法,当存储完成的时候被调用。namespace是键值对所在的名称空间。存储完成之后的回调方法有四个参数:statuskeymessagenamespace,分别表示存储操作的结果、存储时使用的键、额外的出错消息以及存储时使用的名称空间。status可选的值有:dojox.storage.SUCCEEDEDdojox.storage.FAILEDdojox.storage.PENDING,分别表示存储成功、失败和在等待中。
get(key, namespace)根据键来获取值。参数 key表示键,而 namespace表示所在的名称空间。
remove(key, namespace)从名称空间 namespace中删除键为 key的值。
putMultiple(keys, values, resultsHandler, namespace)put()方法作用相同,不同的是一次存储多个键值对。
getMultiple(keys, namespace)get()方法作用相同,不同的是一次获取多个键的值。
removeMultiple(keys, namespace)remove()作用相同,不同的是一次删除多个键。

开发人员可以直接使用 dojox.storage.Provider中的方法,如 dojox.storage.put()就可以存储键值对。代码清单 6中给出了使用 dojox.storage的示例。

清单 6. dojox.storage 示例
 function saveAndLoad() { 
    var value = "Hello World"; 
    dojox.storage.put("testKey", value, function(status) { 
        if(status == dojox.storage.FAILED){ 
            alert("保存失败!"); 
        } else if(status == dojox.storage.SUCCESS){ 
            var loadedValue = dojox.storage.get("testKey"); 
            alert(loadedValue); 
        } 
    }); 
 } 

 if(!dojox.storage.manager.isInitialized()){ 
    dojo.connect(dojox.storage.manager, "loaded", saveAndLoad); 
 } else{ 
    dojo.connect(dojo, "loaded", saveAndLoad); 
 }

代码清单 6所示,首先要通过 dojox.storage.manager.isInitialized()是否以及初始化,如果没有的话,则需要等待 dojox.storage.manager初始化完成之后,再进行存储操作。保存和读取数据分别使用 dojox.storage.put()dojox.storage.get()即可。在使用的时候不需要关心底层具体使用的存储机制实现,dojox.storage.manager会自动选择适合的存储机制实现。

在介绍完浏览器端存储机制之后,下面介绍嵌入对象的支持。

嵌入对象支持

在 Ajax 应用中经常会需要嵌入一些其它组件,如 Flash 和 Quicktime 影片等。dojox.embed模块提供了嵌入这些组件的支持。

dojox.embed.Flash类用来方便的嵌入 Flash 影片。该类的构造方法包含两个参数,第一个是包含一些配置属性的 JavaScript 对象,而第二个参数是显示 Flash 影片的 DOM 节点。初始化时可以指定的配置属性包括:path表示影片的地址,width表示影片的宽度,height表示影片的高度,以及 params表示传递给 Flash 影片的参数等。dojox.embed.Flash提供了一些事件,如 onReady()会在浏览器开始加载影片的时候调用,onLoad()会在影片完成加载之后调用,onError()会在出现错误的时候调用。

dojox.av模块在 dojox.embed模块的基础上提供了方便的在网页上播放视频和音频内容的支持。dojox.av.FLAudio是一个基于 Flash 可以播放 MP3 文件的组件。dojox.av.FLVideo可以用来播放视频文件。

在介绍完嵌入对象的支持之后,下面介绍一些其它的组件。

其它组件

定时器

在 Ajax 应用中会需要定时执行某些任务,通过是通过 JavaScript 里面的 setTimeout()setInterval()来实现的。这两个方法使用起来不是很方便。Dojo 扩展库中的 dojox.timing模块提供了对定时任务的抽象。

dojox.timing模块的核心是 dojox.timing.Timer类,表示一个定时器。dojox.timing.Timer的构造方法接受一个参数 interval表示定时器的间隔时间。它的方法 start()stop()用来启动和停止定时器。当设定的间隔到达的时候,onTick()方法会被调用。使用定时器的时候,只需要用 dojo.connect()onTick()时添加处理即可,如 dojo.connect(timer, "onTick", function() {})

dojox.timing.Sequence用来顺序执行一系列的操作。对每个操作可以定制其重复次数和执行前后的暂停时间。dojox.timing.Sequencego(defs, doneFunction)用来启动要执行的操作,其参数 defs表示的是一个包含待执行操作声明的数组。数组中的每个元素是一个 JavaScript 对象,该对象的属性 func表示待执行的方法,pauseBefore表示在执行前的暂停时间,pauseAfter表示执行后的暂停时间。

全局惟一 ID

dojox.uuid用来生成全局惟一的 ID。生成全局惟一 ID 的方式有很多种,Dojo 扩展库中提供了两种方式,一种是随机生成 ID,通过 dojox.uuid.generateRandomUuid()方法就可以生成。另外一种是基于时间的 ID,通过 dojox.uuid.generateTimeBasedUuid()就可以生成。

字符串操作

在 JavaScript 中对较长的字符串进行操作,一般来说会遇到性能问题,尤其在 IE 浏览器上面。dojox.string.Builder是一个对长字符串进行操作的类。它提供了一系列字符串操作的方法,包括 append(str)concat(str)用来添加字符串,replace(oldStr, newStr)用来替换部分字符串,insert(index, str)用来从指定位置开始插入新的字符串,以及 remove(start, len)用来从指定位置开始删除给定长度的字符串。

dojox.string.sprintf(format, filler)是一个快速对字符串进行格式化的方法,其作用类似于 C++ 里面的 printf方法。比如 dojox.string.sprintf("%d", 100.342)的输出是 100dojox.string.sprintf()的参数 format表示的是字符串的格式化方式,其中支持一些占位符,如空格和 0 可以用来进行填充,+-可以输出数字的正负值,还可以选择数字显示的精度等。

编码

dojox.encoding模块提供了对常见编码方式的支持。dojox.encoding.base64.encode()dojox.encoding.base64.decode()可以用来进行 Base64 方式的编码和解码。dojox.encoding.digests模块支持 MD5 和 SHA1 两种常见的摘要编码方式。摘要编码的结果支持 Base64、十六进制数字和字符串三种输出方式。如 dojox.encoding.digests.MD5(message, dojox.encoding.digests.outputTypes.Hex)输出的是 MD5 编码的十六进制数字。而 dojox.encoding.digests.SHA1(message, dojox.encoding.digests.outputType.String)输出的是 SHA1 编码的字符串。dojox.encoding.crypto模块支持常用的加密方式,包括 RSA、AES 和 Blowfish 等。如 dojox.encoding.crypto.simpleAES.encrypt(message, key)使用 AES 算法对给定的消息进行加密。dojox.encoding.compression模块支持了 LZW 和 splay 两种压缩方式。

总结

Dojo 扩展库提供的丰富组件资源为 Ajax 应用提供了一个很好的基础。当开发人员需要为自己的应用开发一些组件的时候,优先考虑复用 Dojo 扩展库已有的组件,在这些组件的基础上进行简单的定制。除了简单的定制之后,还可以通过扩展已有组件的方式来使用这些组件。本文对 Dojo 扩展库中的常用组件做了简单的介绍,可以为开发人员提供参考。

声明

本人所发表的内容仅为个人观点,不代表 IBM 公司立场、战略和观点。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=604479
ArticleTitle=使用 Dojo 的 Ajax 应用开发进阶教程,第 9 部分: Dojo 扩展库:丰富的组件资源仓库
publish-date=12222010