Dojo 日期控件的国际化和集成


Dojo 控件介绍

  Dojo 日期控件类型

  Dojo 目前支持两种日期控件:

图 1. dijit.form.TimeTextBox

  该类型控件为时间控件 , 图中显示格式为 :hh:mm:ss,该控件支持国际化 , 其格式会根据国家的不同而相应变化。

图 2. dijit.form.DateTextBox

  该类型控件为日期控件 , 图中显示格式为 :yyyy-MM-dd,该控件也支持国际化。

  Dojo 日期控件的类层次结构

图 3. Dojo 日期控件类结构图

  图 3 列出了 Dojo 日期控件所依赖的主要组件,下面分别介绍它们的功能:

  dijit.form._ FormiWidget

  所有 dijit 控件的基类,定义了 Dojo 控件的一些共有特征,如 id,name 属性,onFocus,onChange 事件等。

  dijit.form.TextBox

  普通 html 文本框的一个封装。

  dijit.form.ValidationTextBox

  提供验证功能的文本框 , 子类可重写 isValid() 方法来自定义验证规则。

  dijit.form.MappedTextBox

  提供了一个和文本框对应的隐藏域,用于存放 dojo 内部处理的结果 , 并提供了一个方法 serialize 来在内部值和显示值之间转化。

  dijit.form.RangeBoundTextBox

  可定义取值范围的控件,并提供一个接口 isInRange 来判断是否在给定范围内。

  Dojo 日期控件的初始化

  Dojo 提供了两种初始化控件的途径:声明方式和编程方式。

  声明方式

  通过给 html 控件添加 dojoType 属性,其值为 dojo 控件的类名,在加载页面的过程中 Dojo 会将指定了 dojoType 的控件转为 dojo 控件,如 <input type="text" dojoType="dijit.form.TimeTextBox" id="text001"> 。在页面加载完成后会转变为一个 dojo 时间控件。

  Dojo 是如何把普通的 html 控件转换为 dojo 控件的呢? dojo.parser 在其中起了主要的作用。 dojo.parser 会遍历页面取出有 dojoType 属性的 html 元素,根据 dojoType 的值来初始化 dojo 控件对象,同时会把页面中该元素的属性值做为参数传递给初始化方法,Dojo 把参数值转换为自己需要的类型。例如 :<input type="text" dojoType="dijit.form.TimeTextBox" id="text001" value="T14:22"> 在页面加载的时候 dojo 会初始化 dijit.form.TimeTextBox 类型的控件,同时会把 value="T14:22" 做为参数传给初始化方法,但由于 dijit.form.TimeTextBox 对应的 value 属性的值是 Date 类型,所以 dojo.parser 会对其进行转换。此时会用到 dojo 日期转换功能,在后面会详细介绍,代码如下 :

清单 1. 声明方式初始化 dojo

<script djConfig="parseOnLoad:true,isDebug:true,locale:'zh-cn'"src="<%=Context%> 
 /javascript/dojo/dojo.js" ></script> 
 <script type="text/javascript"> 
 dojo.require("dojo.parser"); 
 dojo.require("dijit.form.TimeTextBox"); 
 </script> 
 <body class="tundra"> 
 <input type="text" id="text001" dojoType="dijit.form.TimeTextBox" value="T14:22">


图 4. Dojo 日期控件类结构图

  编程方式

  dojo 允许以更加面向对象的方式来使用 dojo 控件。对于上面的例子,可以采用如下方式来初始化。

new dijit.form.TimeTextBox( 
 {"id":"text002","value":dojo.date.locale.parse(" 下午 2:22",{selector:"time"})}, 
 dojo.byId("text001"));

  该方法有两个参数 , 第一个为 dojo 对象属性值的一个集合,第二个参数指出了 dojo 控件在页面上的位置,在此例中 id 值为 text001 的 html 元素将被替换为 dojo 控件(注:原来的 html 控件将被移除)。第一个参数中我们同样有两个属性 id 和 value,由于编程方式定义的 dojo 控件不再经过 dojo.parser 处理,因此 value 属性的值必须是日期类型,我们用 dojo.date.locale.parse 方法来将字符串转换为 Date 类型,此处我们会看到同样是把字符串转换为 Date 类型,不同的方法数据格式会有很大不同,稍后会对此进行详细介绍 , 详细代码如下:列表 (lists) 是文章中常用的元素。列表分为有序列表 ( 带有数字顺序的列表 ) 和无序列表 ( 不带数字顺序的列表 ) 。

清单 2. 编程方式初始化 dojo

<script djConfig="parseOnLoad:true,isDebug:true,locale:'zh-cn'"src="<%=Context%> 
  /javascript/dojo/dojo.js" > 
  </script> 
 <script type="text/javascript"> 
  dojo.require("dojo.parser"); 
  dojo.require("dijit.form.TimeTextBox"); 
 </script> 
 <body class="tundra"> 
  <input type="text" id="text001"> 
    <script> 
      new dijit.form.TimeTextBox( 
      {"id":"text002","value":dojo.date.locale.parse 
      (" 下午 2:22",{selector:"time"})},dojo.byId("text001")); 
    </script>


图 5. 编程方式初始化 dojo 效果

  我们可以看到,这两种方式所产生的效果是完全一样的。声明方式定义 dojo 控件实现起来比较简单,而且 dojo.parser 帮助我们做了很多辅助工作。编程方式稍微复杂些,但相比声明方式,编程方式更灵活,我们可以很方便的控制它的初始化过程。

  两种方式结合

  当然有些情况下会有这种需求 , 既想拥有编程方式的灵活性,又想拥有声明方式的简单性,比如我想自己来控制什么时候生成 dojo 控件,又不想自己写方法来进行参数值转换,可通过如下方式来实现,在 html 代码中不添加 dojoType 属性,在我们需要的时候,通过编程方式来指定 html 控件的 dojoType 属性值,然后通过调用 dojo.parser.instantiate() 方法,来解析 html 代码生成 dojo 控件,这样我们既能动态的控制 dojo 控件的生成,又能利用 dojo.parser 的强大功能,对于上面提到的例子我们可采用如下代码实现:

清单 3. 两种方式结合页面代码

<script djConfig="parseOnLoad:true,isDebug:true,locale:'zh-cn'"src="<%=Context%> 
  /javascript/dojo/dojo.js" > 
  </script> 
 <script type="text/javascript"> 
  dojo.require("dojo.parser"); 
  dojo.require("dijit.form.TimeTextBox");  
  function createDojo(inputId){ 
    var inputObj = document.getElementById(inputId); 
    inputObj.setAttribute("dojoType", "dijit.form.TimeTextBox"); 
    dojo.parser.instantiate([inputObj]); 
  } 
 </script> 
 <body class="tundra"> 
  <input type="text" id="text001" onfocus="createDojo('text001')"> 
 </body>

  其页面效果同前两种方式完全一样。

  Dojo 日期控件的国际化策略

  上一节对 Dojo 日期控件做了一个整体介绍,我们了解了 Dojo 的类层次结构以及如何使用 Dojo 。本节主要介绍 Dojo 日期控件对时间的处理以及对国际化的支持。

  Dojo 日期控件对时间的处理

  由于大部分 dojo 控件都继承自同一个基类,所以他们拥有相似的行为方式:

  都通过 onfocus 事件来触发 dojo 控件;

  如果继承自 dijit.form.ValidationTextBox,都通过 onkeyup 事件对值进行校验;

  都通过 onBlur 事件来关闭 dojo 控件等等。

  日期控件同样具有上述行为,相应时间分别为:

  Onfocus:打开日历窗口,并对当前值进行校验;

  Onkeyup:对当前值进行校验;

  onBlur:关闭日历窗口,并对当前值进行校验。

  了解了 Dojo 日期控件的事件,下面将介绍我们 Dojo 提供的用于数据处理的方法 setValue() 和 getValue() 。

  setValue 方法

  在日期控件初始化时会给其传递一个 Date 类型的初始值,在初始化方法中正是通过调用 setValue() 来对其进行付值的 setValue(Date):在该方法中会进行两个操作:用 format 属性定义的方法将 Date 类型数据转换为字符串,存到 textbox 的 value 属性中,textbox 是我们可以在页面看到的 dojo 日期控件中的文本框;用 serialize 属性定义方法将 Date 类型数据转换为字符串存到 valueNode 的 value 属性中,valueNode 既为 textbox 所对应的隐藏域。 dijit.form.TimeTextBox 中默认的 format 方法为 dojo.date.locale.format, serialize 方法为 dojo.date.stamp.toISOString 。

  getValue 方法

  getValue() 方法返回的是日期控件的值类型为 Date 。上面提到 dojo 日期控件的两个域 textbox 和 valueNode 中存储的都是字符串类型数据,因此该方法中会将其转换为 Date 类型 .dijit.form.TimeTextBox 默认使用的是 dojo.date.locale.parse (/*String*/value, /*Object?*/options) 方法该方法会根据指定的 locale( 在 djConfig 中指定 ) 和格式 ( 在输入参数 selector 属性中指定 ) 来将 textbox 中的值转换为 Date 类型。

  Dojo 日期控件对国际化的支持

  Dojo 日期控件对国际化的支持主要集中在 dojo.date 包下的两个类 dojo.date.locale 和 dojo.date.stamp 。

  dojo.date.stamp

  基于 ISO-8601 标准,在 Date 和 String 类型之间进行转换。 ISO-8601 支持的格式如下:

日期 
  yyyy 
  yyyy-MM 
  yyyy-MM-dd 
时间 
  THH:mm 
  THH:mm:ss 
  THH:mm:ss.SSS

  dojo.date.stamp 类中包含的方法为:

  dojo.date.stamp.fromISOString

  用于把 String 转为 Date.

  例 : dojo.date.stamp.fromISOString("2005-06-30T08:05:00");

  转换后的 Date 类型在 Firefox 下用 Firebug 打印的结果如下 :

图 6. Dojo 实际存储的日期值

  而 dojo.date.stamp.fromISOString("2005-06-30 T08:05:00");

  因为不符合 ISO-8601 标准,将产生一个空的 Date 对象。

  dojo.date.stamp.toISOString

  用于把 Date 转为 String

  例:dojo.date.stamp.toISOString(new Date())

  上面提到过,如果采用声明方式生成 Dojo 日期控件,则 Dojo 会用 dojo.date.stamp.fromISOString 方法来对其初始化,因此我们在给控件复值的时候必须遵循 ISO-8601 标准,否则将会生成一个空值 . 如何在初始化时,让 Dojo 接受非标准格式的数据呢?我们知道,Dojo 日期控件用两个域来存放数据 :textbox 和 valueNode,无论初始化时它如何对数据进行处理,最终的结果都是存在这两个域里,所以我们可以将我们的值直接复给这两个域,这样即使 dojo.date.stamp.fromISOString() 方法转换失败,我们也能将值赋给 Dojo 。例如:

清单 4. 直接给 dojo 隐藏域赋值

<script type="text/javascript"> 
  dojo.require("dojo.parser"); 
  dojo.require("dojo.date.stamp"); 
  dojo.require("dojo.date.locale"); 
  dojo.require("dijit.form.TimeTextBox");  
  function createDojo(inputId){ 
    var obj = dojo.byId(inputId); 
    var value = obj.value; 
    obj.setAttribute("dojoType", "dijit.form.TimeTextBox"); 
    dojo.parser.instantiate([obj]); 
    obj = dijit.byId(inputId); 
    obj.textbox.value = value; 
    obj.valueNode.value = value; 
  } 
 </script>

  当然 Dojo 并不推荐我们这样做,毕竟它已经向我们提供了对其值进行操作的接口:setValue() 和 getValue() 。但由于声明方式中我们没有机会接触到这两个方法,所以如果不采用强制复值的方法,我们只能通过编程方式来生成 Dojo 。在编程方式中,我们直接传递一个 Date 对象给 Dojo 而非字符串,所以在传递之前,可以自己定义转换方式来将 String 转为 Date 。

清单 5. 通过 dojo 提供的接口来赋值

<script type="text/javascript"> 
 <script type="text/javascript"> 
  dojo.require("dojo.parser"); 
  dojo.require("dojo.date.stamp"); 
  dojo.require("dojo.date.locale"); 
  dojo.require("dijit.form.TimeTextBox"); 
 </script> 
 <body class="tundra"> 
  <input type="text" id="text001"> 
  <script> 
    new dijit.form.TimeTextBox({"id":"text002","value":dojo.date.locale.parse 
    (" 下午 2:22",{selector:"time"})},dojo.byId("text001")); 
    </script> 
 </body>

  此处用到了 dojo.date.locale.parse 方法,下面会详细介绍。

  Dojo.date.locale

  基于指定的 locale,在 String 和 Date 之间进行转换。

  主要介绍两个方法:dojo.date.locale.parse() 和 dojo.date.locale.format() 。

  dojo.date.locale.parse()

  用于把字符串按照指定参数转换为日期类型

  其中字符串的格式必须和当前页面的 locale 相匹配,否则转换将失败 , 例 :

清单 6. 字符串转换为日期类型代码 1

<script djConfig="parseOnLoad:true,isDebug:true,locale:'zh-cn'" src="<%=Context%> 
  /javascript/dojo/dojo.js" > 
  </script> 
 <script> 
  dojo.date.locale.parse("12:30",{selector: "time"}); 
 </script>

  执行的结果为空,说明转换失败。 因为 locale: zh-cn 对应的时间格式为“下午 12:30 ”如换成如下代码 :

清单 7. 字符串转换为日期类型代码 2

<script djConfig="parseOnLoad: true, isDebug: true, locale:'zh-cn'" src="<%=Context%> 
  /javascript/dojo/dojo.js" > 
  </script> 
 <script> 
  dojo.date.locale.parse(" 下午 12:30",{selector: "time"}); 
 </script>

  则能转换成功。由此可以看到,如果要将字符串转为日期类型,字符串的格式必须和当前页面的 locale 相匹配,这就对转换增加了一些约束。

  dojo.date.locale.format()

  用于把日期类型按照指定的格式转换为字符串。

  在将日期类型转换为字符串时,并不要求必须与 locale 相匹配,因此使用起来更灵活些,例

清单 8. 日期转换为字符串代码 1

dojo.date.locale.format(new Date(), {selector:'time', timePattern:'HH:mm:ss'});

  转换后结果为 : 10:18:41

清单 9. 日期转换为字符串代码 2

dojo.date.locale.format(new Date(), {selector:'date', datePattern:'yyyy-MM-dd'});

  转换后结果为 : 2008-10-10

清单 10. 日期转换为字符串代码 3

dojo.date.locale.format( 
  d,{selector:'datetime', datePattern:'yyyyMMdd',timePattern:'HHmmss'});

  转换后结果为 : 20081010 101841

  上述方法在 Dojo 日期控件中的应用

  上面介绍了 dojo 提供的用于时间处理的一些工具,下面将介绍 dojo 日期控件是如何使用这些工具的。在给 dojo 日期控件负值的时候,会用 format 属性定义的方法将其转化为字符串存到 textbox, 做为显示值用 serialize 属性定义方法将 Date 类型数据转换为字符串 存到 valueNode,做为 dojo 日期控件的实际值在从 dojo 日期控件取值的时候,用 parse 属性定义的方法,将 textbox 中的值转换为 Date 类型。

  format 属性对应的方法为 dojo.date.locale.format, ;

  serializet 属性对应的方法为 dojo.date.stamp.toISOString ;

  parse 属性对应的方法为 dojo.date.locale.parse ;

  format 方法 :dojo.date.locale.format

  会根据指定的格式对 dateObject 进行转换。

  我们可以通过在页面中如下配置来指定 locale: <script djConfig="parseOnLoad: true, isDebug: true, locale:'zh-cn'"> 对于日期格式可在输入参数 options 的 selector 属性中定义。目前 dojo 支持三种格式 :date,time,timestamp 。但 dojo 只对前两种定义了控件类 dijit.form.DateTextBox 和 dijit.form.TimeTextBox,如果我们需要 timestamp 类型的控件可通过扩展 dijit.form.TimeTextBox 来实现,代码如下:

清单 11. 扩展 dojo 日期控件

dojo.declare("dijit.form.TimestampTextBox",dijit.form.TimeTextBox,{ 
  postMixInProperties: function(){ 
    this.inherited('postMixInProperties', arguments); 
    this.constraints.selector = 'timestamp'; 
  } 
});

  当然也可以自定义 format 方法来对 Date 类型进行转换 .

  serialize 方法 : dojo.date.stamp.toISOString

  按照 ISO-8601 标准来对 Date 类型进行转换,转换后的值被存在 valueNode 里,而此值是 dojo 日期控件的真实值,所以如果其格式不能满足我们的要求时,可通过自定义 serialize 方法来解决 , 例:中国时间上午 10:17 在页面中显示为:上午 10:17,如果用默认的 serialize 方法则其真实值为 :T10:17:00, 我们看到时间前多了个 T, 如果我们想最终结果为 10:17:00, 则可如下定义 serialize 方法 .

清单 12. 自定义 serialize 方法

function(d, options) { 
  return dojo.date.locale.format( 
    d, {selector:'time',timePattern:'HH:mm:ss'} 
  ); 
 }

  在上面已经详细介绍了这几个方法,如果在实际应用中,上述方法不能满足要求时,我们可以通过更改相关属性对应的方法来达到目的。同时,我们注意到,上述方法中都有一个 options 参数,该参数是用来指定转换的格式的,它是一个 Object 类型的数据,对应以下属性:selector: 用来指定要转换的类型,dojo 已定义的值有 date( 只转换日期部分 ) 和 time ( 只转换时间部分 ), 如果为其他值则将会把 date 和 time 都包括进来

  formatLength: 转换后字符串的长度 可选值有 long, short, medium , full 默认是 short

  datePattern: 日期部分的格式

  timePattern:时间部分的格式

  locale:设定国际化参数

  与后台系统的集成

  通过以上对 Dojo 日期控件国际化支持的介绍,我们知道 Dojo 作为一种流行的 Javascript 开源框架,其对日期国际化的支持非常强大。目前的很多 Web 应用都是基于 Dojo 来实现日期的国际化。但不是每个后台的系统对日期国际化的支持都是那么强大,有些后台系统可能对日期国际化的支持比较有限,这时如果需要将 Dojo 和这些后台系统进行集成来支持日期国际化的时候,就需要我们做一些额外的开发工作。这里我们以 IBM 的 DB2 Content Manager 来举例说明 Dojo 如果和跟后台系统进行集成,同时我们也给出一些集成方面的开发技巧。

  IBM DB2 Content Manager 对日期国际化的支持:

  DB2 Content Manager 是建立在 DB2 Universal Database? 存储过程基础上的内容储存库,利用了 IBM WebSphere Application Server 提供的内容检索和安全性以及 Tivoli? Storage Manager 提供的对象迁移及备份与恢复。 CM 可作为结构化和非结构化数据的企业储存库用来存储任何格式的文档。 DB2 Content Manager 支持内容国际化 (Globalization),但是对日期类型的国际化支持的并不是很好。比如,对于 Date 类型的数据,CM 要求其格式必须是 yyyy-MM-dd 。 如果某一个国家默认的日期格式是 MM-dd-yyyy,这种格式的日期数据是没法保持到 CM 中的,唯一的办法是将其它日期的格式转成 yyyy-MM-dd 格式,然后再进行保存。下面列出 CM 支持的日期格式:

清单 13. CM 支持的日期格式

Type Format
Date yyyy-MM-dd
Time HH.mm.ss 或 HH:mm:ss
Timestamp yyyy-MM-dd-HH.mm.ss.SSSSSS
或 yyyy-MM-dd HH:mm:ss.SSSSSS

  通过以上对 CM 支持的日期格式的分析,我们可以得出结论:对于要保存到 CM 的日期数据需要先进行格式转化,然后再保存。在使用 Dojo 作为前台,CM 作为后台的 Web 应用程序开发中,Dojo 在前台 Web 页面对日期国际化的支持非常强大,因此需要在 Dojo 日期控件把日期传到后台 CM 时先把日期转成 CM 能够支持的格式,流程图如下:

图 7. Dojo 和 CM 日期转换流程图

  查看原图(大图)

  通过上面的流程图我们可以清楚的知道,在 Dojo 日期控件向 CM 传送日期数据之前需要对日期进行格式转换,下面针对 Date、Time、Timestamp 三种类型的数据分别介绍如何进行日期转换:

  Date

清单 14. Date 类型转换代码

  dojo.declare("MyDateTextBox",[dijit.form.DateTextBox],{ 
  serialize: function(d, options) { 
    return dojo.date.locale.format( 
      d, {selector:'date', 
        datePattern:'yyyy-MM-dd', 
        timePattern:'HH:mm:ss'}).toLowerCase(); 
  }, 
 });

  说明:定义自己的 dojo Date 控件,需要继承 dijit.form.DateTextBox (Dojo 中默认的 Date 控件 ) ;

  重载 dijit.form.DateTextBox 中的 serialize 方法:指定当前控件的类型为 date (selector: ’ date ’),将控件中的 Date 值转成 yyyy-MM-dd 格式。

  Time

清单 15. Time 类型转换代码

  dojo.declare("MyTimeTextBox",[dijit.form.TimeTextBox], { 
  serialize: function(d, options) { 
    return dojo.date.locale.format( 
      d, {selector:'time', 
        datePattern:'yyyy-MM-dd', 
        timePattern:'HH:mm:ss'}).toLowerCase(); 
  }, 
 });

  说明:定义自己的 dojo Time 控件,需要继承 dijit.form.TimeTextBox (Dojo 中默认的 Time 控件 ); 重载 dijit.form.TimeTextBox 中的 serialize 方法 : 指定当前控件的类型为 time (selector: ’ time ’), 将控件中的 Time 值转成 HH:mm:ss 格式。

  Timestamp

清单 16. Timestamp 类型转换代码

dojo.declare("MyTimestampTextBox",[dijit.form.TimeTextBox], { 
  serialize: function(d, options) { 
    return dojo.date.locale.format( 
      d, {selector:'datetime', 
        datePattern:'yyyy-MM-dd', 
        timePattern:'HH:mm:ss'}).toLowerCase() + ".000000"; 
  } 
 });

  说明:定义自己的 dojo Timestamp 控件,需要继承 dijit.form.TimeTextBox (Dojo 中默认的 Time 控件 ); 重载 dijit.form.TimeTextBox 中的 serialize 方法 : 指定当前控件的类型为 datetime (selector: ’ datetime ’), 将控件中的 Timestamp 值转成 yyyy-MM-dd HH:mm:ss.SSSSSS 格式 , 本例中将最后的六位微秒统一置为 0, 因为在平时的应用中基本不会使用到后面的微秒,当然也可以根据实际的需要置成不同的值。

  总结

  Dojo 是一个功能丰富,易于扩展的 JavaScript 工具包,同时提供了面向对象的编程模式。本文主要介绍了 dijit 包下的日期控件,对其框架结构,使用方式,扩展点都作了详细介绍。通过本文的学习相信可以使您在项目中熟练的使用 dojo 日期控件,同时在学习使用其他 dojo 控件时,也为您提供了很好的学习思路


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3