Marco Lerro,高级工程师,IBM,Software Group Roberto Longobardi,软件开发人员,Software Group Gianluca Perreca,Software Group Alessandro Scotti,顾问软件工程师,Software Group
2009 年 7 月 13 日
学习使用 Dojo JavaScript 工具箱开发 HTML 小部件的基础知识。本文为您提供了一个简介,此外,还给出了几个例子为开发过程提供帮助 — 以简单的示例小部件开始,随后是复杂一些的小部件,同时还突出介绍了在开发过程中可能遇到的一些常见问题。
简介
本文的目标是为您提供使用 Dojo JavaScript 工具箱开发 HTML 小部件的基础知识,首先从版本 1.0 开始。本文还描述了几个示例,以简单的小部件开始,之后是较为复杂的小部件,同时还会解决在小部件开发过程中经常遇到的一些常见问题。
回页首
何为 Dojo 工具箱?
Dojo 是一种基于 JavaScript 的开源工具箱,可用来开发动态 HTML Web 应用程序。借助它,可以快速构建较标准 HTML 小部件更为复杂的小部件。使用 Dojo 提供的组件可以让 Web 用户界面的可用性、响应性和功能性都有所提高。由 Dojo 提供的低层 API 和兼容性层可帮助您编写跨浏览器兼容的应用程序。
dojo.declare(
"widgets.TextBox",
[dijit._Widget,dijit._Templated],
{
/** the template path */
templatePath: dojo.moduleUrl("widgets","templates/TextBox.html"),
/** the input DOM node */
inputNode: null,
/** the label */
label: "",
/** onkeyup handler */
onKeyUp: function() {
// give a chance to the browser to update the DOM
setTimeout(dojo.hitch(this,this.validate),0);
},
/** validate function */
validate: function() {
if ( this.inputNode.value === "Ok" ) {
// the text is correct
dojo.addClass(this.inputNode,"inputOk");
dojo.removeClass(this.inputNode,"inputError");
} else {
// the text is incorrect
dojo.removeClass(this.inputNode,"inputOk");
dojo.addClass(this.inputNode,"inputError");
}
}
}
);
属性值标识包含目标 DOM 节点的小部件属性名。如果指定的是一个空字符串,那么就会使用 domNode 。
清单 9 给出了一个示例
清单 9. 声明一个 dojo 小部件
dojo.declare(
"MyWidget",
dijit._Widget,
{
// the attribute to map (name and value)
title: "myTitle",
// the DOM node to be used to set the
// title attribute to the "myTitle" value
titleNode: null,
// the attribute map
// the title attribute is mapped to the titleNode
attributeMap: {title: "titleNode"},
// the template string
templateString: "<div><span dojoAttachPoint=/"titleNode/"></span></div>",
得到的小部件模板将是:
<div><span title="myTitle"></span></div>
请注意,由于 base _Widget 类已经映射了某些基本的 HTML 属性(如 ID、类、样式),因此实现者不能覆盖 attributeMap 属性。相反,它们必须混合基础类 attributeMap 属性与它们的值。清单 10 显示了从 _FormWidget 类中检索出来的一个示例。
如前面看到的,小部件必须继承自 dijit._Widget 类,它定义并提供了 Dojo 小部件的基本行为。这样一个基类定义了负责构建小部件呈现元素的 buildRendering 方法。比如,一个小部件实现者可以用这种方法创建小部件标记并将其设置到小部件 DOM 节点。另一种方案是使用 DOM API 创建小部件结构。在这两种情况下,实现者都必须以某种方式编程实现 buildRendering 方法。
在前一篇文章中(“The Abstract User Interface Markup Language Web Toolkit: An AUIML renderer for JavaScript and Dojo”,参见 参考资料 ),我们介绍了如何用 AUIML 工具箱设计面板以及如何用 AUIML Web Toolkit(AWT)在 JavaScript 内实现逻辑代码。图 4 显示了 AUIML 面板:
图 4. AUIML 面板
让我们着重看看 Valid from 字段。它已经在 AUIML 编辑器中被定义为 Edit Box,Date;AWT 通过清单 15 所示的 HTML 代码连接此元素。
dojo.require("ajaxcommon.resources.Images");
dojo.require("ajaxcommon.widgets._DateTimePicker");
dojo.require("ajaxcommon.widgets.picker.PickerInputBox");
dojo.require("ajaxcommon.widgets.picker.DatePicker");
dojo.declare(
"ajaxcommon.widgets.DateInputBox",
[ajaxcommon.widgets.picker.PickerInputBox,
ajaxcommon.widgets._DateTimePicker],
{
/** the picker icon */
pickerIcon: ajaxcommon.resources.Images.get()["CALENDAR_ICON"],
/** the picker disabled icon */
pickerDisabledIcon: ajaxcommon.resources.Images.get()["DISABLED_CALENDAR_ICON"],
/** the picker icon title */
pickerIconTitle: ajaxcommon.resources.Labels.get()["PICK_DATE"],
/** constraints */
constraints: {selector: "date",formatLength: "short",wideYear: true},
/**
* Constructor.
*/
constructor: function()
{
// even if the format length is short,ensure the wide year (yyyy)
// by overriding the datePattern
if (this.constraints.formatLength === "short" && this.constraints.wideYear) {
this.constraints.datePattern = this._getWideDatePattern();
}
// set the regex for the text
this.textRegExp = "^(" + dojo.date.locale.regexp(this.constraints) + “){0,1}$";
// set the regex message for the text
this.textRegExpMessage =
this._labels.format("DATE_INVALID_VALUE",{example: this._getExampleValue()});
// set the picker class
this.pickerClass = "ajaxcommon.widgets.picker.DatePicker";
},
/**
* Returns the date pattern with the wide-year (yyyy)
*/
_getWideDatePattern: function()
{
// get the bundle
var bundle = dojo.date.locale._getGregorianBundle();
// get the pattern
var pattern = bundle["dateFormat-short"];
// replace the yy to yyyy if not yet yyyy
if ( pattern.search(/yyyy/gi) === -1 ) {
// the year is not in the wide form
pattern = pattern.replace(/yy/gi,"yyyy");
}
return pattern;
},
/**
* Returns a string containing an example of accepted value.
*/
_getExampleValue: function()
{
// get a sample date object (my birthday!!!)
var d = new Date();
d.setDate(15);
d.setMonth(4);
d.setYear(1971);
// format the date in the current locale and return
return dojo.date.locale.format(d,this.constraints);
}
}
);