精华内容
下载资源
问答
  • dojo常用组件案例

    2018-05-15 14:07:19
    dojo作为一个JavaScript框架,使用量个人感觉很少,使用文档也不想jQuery那样全面。最近在做政府项目时,调用政府的本地地图,要用arcgis for js,而arcgis for js就是建立在dojo上开发的。于是研究了一下dojo。。。...

    dojo作为一个JavaScript框架,使用量个人感觉很少,使用文档也不想jQuery那样全面。最近在做政府项目时,调用政府的本地地图,要用arcgis api for js,而arcgis for js就是建立在dojo上开发的。于是研究了一下dojo。。。

    上代码:

        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
        <html>  
            <head>  
                <title>注册案例</title>  
                <style type="text/css">  
                @import "dojo/resources/dojo.css";  
                @import "dijit/themes/tundra/tundra.css";  
                .dijitInputFieldFocused {  
                    border: solid 2px #FFDF00;  
                }  
                </style>  
          
                <script type="text/javascript" djConfig="parseOnLoad: true"  
                    src="dojo/dojo.js"></script>  
                      
                <script type="text/javascript">  
                    dojo.require("dijit.form.Button");  
                    dojo.require("dijit.form.TextBox");  
                    dojo.require("dijit.form.DateTextBox");  
          
                    dojo.require("dijit.form.CheckBox");  
                    //下拉列表  
                    dojo.require("dijit.form.FilteringSelect");  
                    //数字选项  
                    dojo.require("dijit.form.NumberSpinner");  
                    //验证  
                    dojo.require("dijit.form.ValidationTextBox");  
                       dojo.require("dojox.validate.regexp");  
                    //解析器  
                    dojo.require("dojo.parser");  
                </script>  
            </head>  
          
            <body class="tundra">  
                <form id="registForm" method="post">  
                    <table>  
                        <tr>  
                            <td>  
                                <label for="username">  
                                    用户名  
                                </label>  
                            </td>  
                            <td>  
                                <input dojoType="dijit.form.TextBox" type="text" id="username" name="username"/>  
                            </td>  
                        </tr>  
                        <tr>  
                            <td>  
                                <label for="password">  
                                    密码  
                                </label>  
                            </td>  
                            <td>  
                                <input dojoType="dijit.form.TextBox" type="password" id="password" name="password"/>  
                            </td>  
                        </tr>  
                        <!-- 单项选择按钮 -->  
                        <tr>  
                            <td>  
                                <label for="sex1">  
                                    性别  
                                </label>  
                            </td>  
                            <td>  
                                <input dojoType="dijit.form.RadioButton" type="radio" name="sex"  
                                    id="sex1" value="男" checked="checked"/>  
                                <label for="sex1">  
                                    男  
                                </label>  
                                <input dojoType="dijit.form.RadioButton" type="radio" name="sex"  
                                    id="sex2" value="女" />  
                                <label for="sex2">  
                                    女  
                                </label>  
                                <input dojoType="dijit.form.RadioButton" type="radio" name="sex"  
                                    id="sex3" value="保密" />  
                                <label for="sex3">  
                                    保密  
                                </label>  
                            </td>  
                        </tr>  
                        <!-- 年龄 -->  
                        <tr>  
                            <td>  
                                <label for="age">年龄</label>  
                            </td>  
                            <td>  
                                <input dojoType="dijit.form.NumberSpinner"  
                                    value="18"  
                                    class="medium"  
                                    constraints="{max:100,places:0}"  
                                    name="age"  
                                    id="age"  
                                    required="true">  
                            </td>  
                        </tr>  
                        <!-- 日历 -->  
                        <tr>  
                            <td>  
                                <label for="birthday">  
                                    出生日期  
                                </label>  
                            </td>  
                            <td>  
                                <input id="birthday" value="1900-01-01" name="birthday"  
                                dojoType="dijit.form.DateTextBox"  
                                constraints="{min:'1900-01-01',max:'today',formatLength:'long'}"  
                                required="true"  
                                trim="true">  
                            </td>  
                        </tr>  
                        <!-- 多项选择按钮 -->  
                        <tr>  
                            <td>  
                                <label for="interest1">  
                                    兴趣  
                                </label>  
                            </td>  
                            <td>  
                                <input type="checkbox" dojoType="dijit.form.CheckBox"  
                                    name="interest" id="interest1" value="电脑">  
                                <label for="interest1">  
                                    上网  
                                </label>  
                                <input type="checkbox" dojoType="dijit.form.CheckBox"  
                                    name="interest" id="interest2" value="游泳">  
                                <label for="interest2">  
                                    游泳  
                                </label>  
                                <input type="checkbox" dojoType="dijit.form.CheckBox"  
                                    name="interest" id="interest3" value="网球">  
                                <label for="interest3">  
                                    网球  
                                </label>  
                                <input type="checkbox" dojoType="dijit.form.CheckBox"  
                                    name="interest" id="interest4" value="看书">  
                                <label for="interest4">  
                                    看书  
                                </label>  
                            </td>  
                        </tr>  
                        <!-- 下拉列表 -->  
                        <tr>  
                            <td>  
                                <label for="nationality">  
                                    国籍  
                                </label>  
                            </td>  
                            <td>  
                                <select dojoType=dijit.form.FilteringSelect name="nationality"  
                                    id="nationality" hasDownArrow="true">  
                                    <option value="chinese">chinese</option>  
                                    <option value="USA">USA</option>  
                                    <option value="English">English</option>  
                                </select>  
                            </td>  
                        </tr>  
                        <!-- email -->  
                        <tr>  
                            <td>  
                                <label>E-mail</label>  
                            </td>  
                            <td>  
                                <input id="email" type="text" name="email" class="long" value="youname@qq.com"  
                                    dojoType="dijit.form.ValidationTextBox"  
                                    regExpGen="dojox.regexp.emailAddress"  
                                    trim="true"  
                                    required="true"  
                                    invalidMessage="E-mail地址是非法的。" />  
                            </td>  
                        </tr>  
                    </table>  
                </form>  
                <button dojoType="dijit.form.Button">  
                                提交  
                    <script type="dojo/method" event="onClick">  
                                function registCallBack(data,params){  
                                    dojo.byId("showData").innerHTML = data;  
                                }  
                                function registError(data,params){  
                                    dojo.byId("showData").innerHTML = '服务器错误';  
                                }  
                                dojo.xhrPost({  
                                    url:'./regist.do',  
                                    load:registCallBack,  
                                    error:registError,  
                                    form:'registForm',  
                                    encoding:'utf-8'  
                                });  
                    </script>  
                </button>  
                <div id="showData"></div>  
            </body>  
        </html>  
    关于dojo toolkit可以上官网下载,我的版本比较低1.5,新版本写法可能不一样。
    展开全文
  • Dojo 日期控件的国际化和集成 分类: Dojo2010-11-13 14:31 888人阅读 评论(1) 收藏 举报 dojodatetextbox编程functionmanager   Dojo 日期控件类型  Dojo 目前支持两种日期控件: ...

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

    分类: Dojo   888人阅读  评论(1)  收藏  举报

     

    Dojo 日期控件类型

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

    图 1. dijit.form.TimeTextBox
    Dojo 日期控件的国际化和集成

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

    图 2. dijit.form.DateTextBox
    Dojo 日期控件的国际化和集成

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

      Dojo 日期控件的类层次结构

    图 3. Dojo 日期控件类结构图
    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 允许以更加面向对象的方式来使用 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 控件实现起来比较简单,而且 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 日期控件的国际化和集成

      而 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 支持的日期格式

    TypeFormat
    Dateyyyy-MM-dd
    TimeHH.mm.ss 或 HH:mm:ss
    Timestampyyyy-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 日期控件的国际化和集成

      查看原图(大图)

      通过上面的流程图我们可以清楚的知道,在 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 控件时,也为您提供了很好的学习思路

    展开全文
  • 改造dojo 日期控件

    2008-05-23 10:45:07
    dojo._hasResource["bad.form.DateBox"]) { //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["bad.form.DateBox"] = true; dojo....
    if (!dojo._hasResource["bad.form.DateBox"]) { //_hasResource checks added by build. Do not use _hasResource directly in your code.
        dojo._hasResource["bad.form.DateBox"] = true;
        dojo.provide("bad.form.DateBox");    
        
        dojo.require("dijit._Calendar");
        dojo.require("dijit.form.TimeTextBox");
        dojo.require("bad.form._MonthPicker");   
        dojo.require("dojo.date.locale");     
        
        dojo.declare("bad.form.DateBox", [dijit.form.TimeTextBox], {
            /** @attr: 弹出窗口类型  */
            _popupClass: "dijit._Calendar",
            
            /** @attr: {String}日期类型 
            * @example yyyy_MM_dd   其中MM要大写        
            */
            datePattern: "",
            
            /** {String } */
    		_pattern: "",
    				        
            /**@attr: 年的开始位*/
            _yearStart:"",
            
    		/**@attr: 年的结束位*/
            _yearEnd:"",
            
            /**@attr: 月的开始位*/
            _monthStart:"",
            
            /**@attr: 月的结束位*/
            _monthEnd:"",
            
            /**@attr: 日的开始位*/
            _dateStart:"",
            
            /**@attr: 日的结束位*/
            _dateEnd:"",
            
            /**@attr: 存储用户提示信息*/
            _currentMessage: "请输入正确的日期",
            
            /**@attr: {Boolean} 是否显示day 为{false}时不显示,为{true}时显示  */
            showDay: "",        
            
            
            /**@attr: 日期可以显示的初始值*/
    		firstValue:'', 	
    		
           
            /**@method将目前this.textbox.value进行格式化*/
            formatInput: function()
            {       	    		
    	        var value=this.getFormatDate();
    	        if(value instanceof Date)  
    	        {  	
    	            this.setValue(value);  	            
            	}
            }, 
            
            /**   当文本框失去焦点事件*/
            _runBlur: function()
            {        	
            	this.formatInput(); 
            	this.onChange(this.textbox.value);       	
            },
            
            /** @method: 将参数或者目前显示的数字格式化,如果显示中数字位数超过6且显示天数,则将字符截取为yyyy(M)M(d)d 		 
            * @return: {Date} 
            * @remind: 可以自己添加返回值,比如判断现有的值无法转化,返回false,等等。
             */
            getFormatDate: function(value)
        	{    		
        		if(!value)
        		{
                	value = this.textbox.value;
        		}           
                if (typeof value == "string") 
                {
                    var numValue = "";
                    value.replace("-", "");
                    var stringArray = value.split("");                
                    //取得value中的数字			
                    for (var i = 0; (i < stringArray.length && (this.showDay ? numValue.length < 8 : numValue.length < 6)); i++) {                   
                        if (!isNaN(stringArray[i])) {
                            numValue += stringArray[i];
                        }
                    }
                    //如果显示day                
                    if (this.showDay) {                	
                        if (numValue.length == 8) 
                        { 	
                            return new Date(numValue.slice(this._yearStart, this._yearEnd), numValue.slice(this._monthStart, this._monthEnd) - 1, numValue.slice(this._dateStart, this._dateEnd));
                        }
                        if (numValue.length == 7)
                        {
                            return new Date(numValue.slice(this._yearStart, this._yearEnd), numValue.slice(this._monthStart, this._monthEnd-1) - 1, numValue.slice(this._dateStart-1, this._dateEnd));
                        }
                        if (numValue.length == 6) 
                        {
                            return new Date(numValue.slice(this._yearStart, this._yearEnd), numValue.slice(this._monthStart,this._monthEnd-1) - 1, numValue.slice(this._dateStart-1, this._dateEnd-1));
                        }
                    } else {
                        if (numValue.length == 6) {
                            return new Date(numValue.slice(this._yearStart, this._yearEnd), numValue.slice(this._monthStart, this._monthEnd) - 1);
                        }
                        if (numValue.length == 5) {
                            return new Date(numValue.slice(this._yearStart, this._yearEnd), numValue.slice(this._monthStart,this._monthEnd-1) - 1);
                        }
                    }                
                }              		
        	},    
                   
            
            /**@member: 扫描datePattern,获得年月(日)的位置*/
            scanPattern: function()
            {        
            	this._pattern="";        	
            	for(var i=0;i<this.datePattern.length;i++)
            	{
            		switch(this.datePattern.charAt(i))
            		{
            			case 'd':        						
            						while(this.datePattern.charAt(i)=='d')
            						{        							
            							this._pattern+='d';
            							i++;
            						}      
            						i--;  					
            						break;
            			case 'D':        						
            						while(this.datePattern.charAt(i)=='D')
            						{        							
            							this._pattern+='d';
            							i++;
            						}      
            						i--;  					
            						break;
            			case 'M':        						
            						while(this.datePattern.charAt(i)=='M')
            						{        							
            							this._pattern+='M';
            							i++;
            						}    
            						i--;    						
            						break;
            			
            			case 'y':        						
            						while(this.datePattern.charAt(i)=='y')
            						{        							
            							this._pattern+='y';
            							i++;
            						}     
            						i--;   						
            						break;
            			case 'Y':        						
            						while(this.datePattern.charAt(i)=='Y')
            						{        							
            							this._pattern+='y';
            							i++;
            						}     
            						i--;   						
            						break;
            			default :  break;          //暂时不进行处理
            		}
            	}  
            	for(var i=0;i<this._pattern.length;i++)
            	{
            		switch(this._pattern.charAt(i))
            		{
            			case 'd':
            						this._dateStart=i;
            						while(this._pattern.charAt(i)=='d')
            						{
            							i++;        							
            						}
            						this._dateEnd=i;
            						i--;        						
            						break;
            			case 'M':
            						this._monthStart=i;
            						while(this._pattern.charAt(i)=='M')
            						{
            							i++;        							
            						}
            						this._monthEnd=i;
            						i--;        						
            						break;
            			
            			case 'y':
            						this._yearStart=i;
            						while(this._pattern.charAt(i)=='y')
            						{
            							i++;        						
            						}
            						this._yearEnd=i;
            						i--;        						
            						break;
            			default :  break;          //暂时不进行处理
            		}
            	}  
            	console.log(this.datePattern+"  "+this._yearStart+"  "+this._yearEnd+"  "+this._monthStart+"  "+this._monthEnd+"  "+this._dateStart+"  "+this._dateEnd);      	
            },
            
            
            _setPattern: function()
            {
            	/*
            	this._pattern="";            	
                var size=this._yearEnd>this._monthEnd?(this._yearEnd>this._dateEnd? this._yearEnd:this._dateEnd):(this._monthEnd>this.dateEnd? this._monthEnd:this._dateEnd);
                console.log("length is "+size);
                for(var i=0;i<size;i++)
                {
                	if(i>=this._yearStart&&i<this._yearEnd)
                	{
                		while(i<this._yearEnd)
                		{
                			this._pattern+="y";
                			i++;
                		}
                		i--;
                	}
                	else	
                	if(i>=this._monthStart&&i<this._monthEnd)
                	{
                		while(i<this._monthEnd)
                		{
                			this._pattern+="M";
                			i++;
                		}
                		i--;
                	}
                	else
                	if(i>=this._dateStart&&i<this._dateEnd)
                	{
                		while(i<this._dateEnd)
                		{
                			this._pattern+="d";
                			i++;
                		}
                		i--;
                	}            	
                }
                */
                console.log("pattern is "+this._pattern);
            },
            
            /**被绑定的onkeydown事件,火狐下回车事件有问题         
             * */
            _onkeydown: function(key)
            {
            	var c = String.fromCharCode(65);
            	var code=this._getKeyCode(key);
            	if(code==13)
            	{
            		var value=this.getFormatDate();
            		if(value instanceof Date)
                    {
                    	var isie = (document.all) ? true : false;
    					var eSrc =isie?key.srcElement:key.target;
    					if(eSrc.tagName=="INPUT" && (eSrc.type=="text"||eSrc.type=="password"))
    					{
    						if(isie)
    						{
    							key.keyCode=9;
    						}
    						else
    						{
    							key.which=9;
    						}	
    						if(this._opened)
    						{					
    							this._close();
    						}
    					}
                    }
            	}
            	return true;
            },
            
            _getKeyCode: function(e){
                var isie = (document.all) ? true : false;
                var key="";
                if (isie) 
                {
                    key = e.keyCode;
                }
                else
                {
                    key = e.which;                
                    if (key == 120 || key == 228||key == 99 ||key == 0)
                    {
                        key = 8;
                    }
                }
                return key;
            },
            
            /** @method: 过滤字符加捕获回车*/
            keycodefilter: function(key){
                if (key.keyCode == dojo.keys.ENTER) 
                {
                    this.formatInput();      
                    this.onChange();          
                }
                if(key.keyCode==dojo.keys.ESCAPE)         
        		{
        			if(this._opened)
        			{
        				this._close();
        			}	
        		}   		  
             },       
          
           
            /** @method: 验证,目前继承父类的验证方法*/
            validate: function(){
                this.inherited('validate', arguments);
            },      
            
            
            /**  @method: 配置属性,继承父类的同名方法,目前主要是完成 this.datePattern默认配置将其配置为"yyyy-MM-dd"
             */          
            postMixInProperties: function()
            {        	
                this.inherited('postMixInProperties', arguments);
                this.constraints.selector = 'date';                                
                this.datePattern=this.datePattern? this.datePattern:"yyyy-MM-dd";               
                this.showDay = (this.datePattern.indexOf("dd") != -1 || this.datePattern.indexOf("DD") != -1) ? true : false;     //是否显示day   
                this.constraints.datePattern = this.datePattern;
                if(!this.showDay)
                {
                	this._popupClass="bad.form._MonthPicker";
                }
                this.maxLength=this.datePattern.length;   //输入长度不能超过验证长度    
                this.promptMessage="请输入形如"+this.datePattern;
    			this.invalidMessage="请输入形如"+this.datePattern;               
            },        
            
            /** @method: 继承父类同名方法,扫描格式,添加两个事件绑定,一个是键盘输入字符过滤,另一个是失去焦点对字符串进行格式化 如果有初值赋上初值*/
            postCreate: function(){
                this.inherited('postCreate', arguments);          
                this.scanPattern();   
                this._setPattern();     
                dojo.connect(this.textbox, "onkeypress", this, this.keycodefilter); //绑定onkeypress事件        
    			dojo.connect(this.textbox,"onkeydown",this,this._onkeydown);
                dojo.connect(this, "_onBlur", this, this._runBlur);		//绑定失去焦点事件和字符格式化方法
                this._lastValue=" ";
                if(this.firstValue)
                {
                	this.setValue(this.firstValue);      //赋上初值          	      	
                }                    
            },
            
            _onMouserOver: function(evt){
                this.displayMessage(this._currentMessage);
            },
            _onMouserOut: function(evt){
                dijit.hideTooltip(this.domNode);
            },        
             
            /** @method: 验证,目前继承父类的验证方法
             * @param: {Date}newValue
             * */
            onChange: function(newValue)
            {  
            	this._lastValue=this.getValue();        	
    			this.inherited('onChange', arguments);       
            },   
            
            /** @method: 将目前的显示值经过格式化返回  表单进行数据绑定会调用此方法获取当前值
            	@return: {Sring}  被格式化的值 
            */
            getValue: function()
            {        	
            	if(!this.textbox.value)
                {
                	return "";
                }              
            	return this.textbox.value; 	
            },        
            
            /**  @method: 对this.textbox赋值  参数可以是Date对象或者String 若果能转换为Date对象,则显示值改变
             *   @param:  {String}value or {Date}value
             *	 @return: {null}
             */
            setValue: function(value)
            {        	 	
            	//以下为没有弹出窗口对象时,新建一个弹出窗口对象并进行赋值防止出现NaN的情况 
            	if(!this._picker)
            	{
            		this._open();
            		this._close();
            	}    	      	
                var v = [];                         
    			if (value instanceof Date) 
    			{					
    	           v[0] = value;
                }   
    			else if (typeof value == "string") 
    			{			
    				if(value.length==0)
                    {
                    	this.textbox.value="";
                    	return;
                    }
                    else                 	
    				if (value.length >= 6) 
    				{				
                        //setValue的类型为Date对象方能成功
                        v[0]=new Date();                                   
                        v[0]=this.getFormatDate(value);                     	                                       
                    }
                }   
                console.log("v[0] is "+v[0]);
                console.log(v[0] instanceof Date&&v[0].getFullYear());            
                this.inherited("setValue", arguments, v);        
                if(v[0] instanceof Date&&v[0].getFullYear())
                {           	
                	//var testValue=dojo.date.locale.format(v[0],this._pattern);            	
                	if(this._lastValue!=this.textbox.value)
                	{            		
                		this._lastValue=this.textbox.value;
                		console.log("_lastValue is "+this._lastValue);
                	}
                }             
            }        
        });
    }
    

     原先改写了下dojo的日期控件,没太用心,做个反面例子。

    代码如下,上级文件夹“包”叫bad.form,具体对象名字为“DateBox”

     

     

      

     

    bad.form.DateBox

                  属性

    属性名

    类型

    默认值

    描述

    Id

    String

    组件标识

    jsId

    String

    通过jsId可以获得控件对象

    _popupClass

    String

    "dijit._Calendar"

    弹出窗口类型

    datePattern

    String

    “yyyy-MM-dd”

    设置日期格式

    dateValue

    Date

    new Date()即此时此刻

    日期值

     

     

     

     

     

     

     

     

     

    备注

    目前_popupClass可选类型为"dijit._Calendar"”bad.form._MonthPicker”两种,前一种完整显示年月日,后一种只显示年月。

    datePattern设置日期验证的格式以及正确日期的显示格式以及按回车键对现有字符串中数字进行格式化的格式。可以设为”*yyyy*MM*dd*”或者”*yyyy*MM*”其中*可以代表除英文字符以外的任意字符串,MM必须要大写,如果datePattern”*yyyy*MM*”,则_popupClass会变为_popupClass

                  方法

    方法名

    参数

    返回值

    描述

    setValue

    {String or Date}value

    对控件赋值

    getValue

    String

    获取控件的值

    _open

    弹出窗口

    _close

    关闭窗口

     

     

     

     

     

     

     

     

    备注

           setValue要求参数为Javascript的内置对象Date或者能转化为DateString(如2000-10-11 00:00:00:0

           getValue默认返回形如"yyyy-MM-dd"String,此方法可以重写,以需要的格式将值返回。

     

         

                  事件

     

    事件名参数返回值描述
    onValueChange{Date}newValue,{Date}oldValue值改变事件

    展开全文
  • 掌握 Dojo 工具包,第 5 部分: Dojo 的 UI 组件库 原文:http://www.ibm.com/developerworks/cn/web/wa-lo-dojointro5/ 2008 年 11 月 21 日 这一期的 掌握 Dojo 系列 文章将主要讲述 Dojo 工具包的 UI ...

    掌握 Dojo 工具包,第 5 部分: Dojo 的 UI 组件库

    原文:http://www.ibm.com/developerworks/cn/web/wa-lo-dojointro5/

    2008 年 11 月 21 日

    这一期的 掌握 Dojo 系列 文章将主要讲述 Dojo 工具包的 UI 组件库 - Dijit 中类型多样的 Widget 及其使用方法。

    Dijit 简介

    从 Dojo 0.9 开始,Dojo 把 Widget 从 Dojo 的核心包中分离出来,组成 Dijit 。 Dojo 在 Dijit 中为 Widget 家族添加了多位成员,增强了 Widget 的实力的同时也加快了其在页面中的加载速度。

    为改善 Widget 的外观,Dijit 提供了多套样式主题,比如默认绑定的样式主题 Tundra,提高页面可访问性的样式主题 A11y,以及其它两种可供选择的主题 Soria 和 Nihilo 。并且开发人员还可以根据自身项目的需求开发个性化的主题。同时 Dijit 对国际化和针对残障人士的可访问性的支持成度很高。可以说 Dijit 已成为 Dojo 工具包中三辆马车之一。

    本文将会详细介绍 Dijit 中的 Widget 的使用。由于 Dojo Widget 数量众多,不能一一介绍。为此从功能的角度把 Widget 分为三类:表单 Widget,布局 Widget,高级 Widget 。在每个类别中选择代表性的 Widget 结合示例加以介绍。

    表单 Widget 的使用

    在有用户概念的 Web 应用中,注册是一项必不可少的功能,同时注册也是有点枯燥的任务。有个不争的事实就是:没人喜欢填表单——无论是网上还是网下。所以设计有效的页面表单不是件容易的事情。如果不能改变注册表单存在的事实,那么就要改变表单枯燥令人生厌的现状,让表单或整个注册过程变得轻松省力。为实现这个目标,Web 开发人员会把较长的注册表单设计成标签的形式;当用户填错信息时,利用 Javascript 和正则表达式的结合给用户一些提示信息;设计方便的日期选择组件等等。可是这些提高用户友好性的努力往往会给开发人员增加很大的工作量,并且确保这些组件的浏览器无关性也不是一件容易的事情。

    有没有更简便的方法来开发 Web 表单呢?当然有!Dijit 为 Web 开发人员提供了一系列的表单 Widgets,利用这些表单 Widgets,Web 开发人员可以轻松的设计出功能强大、用户友好性高的表单。

    表单 Widget 简介

    可以说每一个 HTML 表单控件都可以在 Dijit 找到与其对应的表单 widgets 。下面列表列出了目前 Dijit 提供的 Form Widgets:

    • Form – 类似于 HTML 的 [form] 控件,同时提供了一些有用的方法和扩展点;
    • Button – 类似于 HTML 的 [button] 风格的控件,同时增加了一些高级的特性;
    • CheckBox
    • RadioButton
    • ToggleButton
    • ComboBox – 类似于 HTML 的 [select] 组合框和 [text] 域控件的结合体。可以像 [select] 组合框那样提供一列可选值;同时允许用户忽略这些可选值,而像在 [text] 域控件里那样输入自己想要输入的任何值;
    • FilteringSelect – 类似于 HTML 的 [select] 控件,可以动态填充可选项,并且可以按需设置加载选项的数量;
    • Textbox – 类似于 HTML 的 [text] 控件,同时提供一系列很酷的功能:可以裁空,改变大小写,设置必填,验证输入合法性,日期组件等;
    • Validation
    • Currency
    • Date, Time
    • Integer
    • Textarea – 类似于 HTML 的 [textarea] 控件,同时可以根据文本的容量动态调整自己的大小,达到了真正的按需分配空间;
    • Slider – 这个 widget 没有相对应的 HTML 控件,是一个相对独立的图形化的组件,可以通过鼠标、方向键来控制刻度尺的刻度。
    • NumberSpinner – 数字转轴,应用此 widget,会让数字的输入更方便,可以通过输入框右侧的上下按钮(支持键盘上下方向键)来调节数字大小。

    所有的这些表单 widgets 都可以放置在 HTML 的 [form] 标签内,也可以放在 dijit.form.Form widget 内,甚至可以放在 [form] 标签外。这些表单 widgets 拥有标准的 HTML 控件的所有属性和方法,在实际开发中可以完全取代标准的 HTML 控件。同时它们都继承于 dijit.form._FormWidget,所以这些表单 widgets 还统一拥有一些附加的属性和方法。下表是它们共有的属性和方法:


    表 1. dijit.form._FormWidget 属性和方法

    属性 属性类别 描述
    disabled Boolean判断此 widget 是否响应用户的输入,如果为真则此 widget 不响应用户的输入。可以用方法setAttribute("disabled", true/false) 来改变此属性值。
    intermediateChanges Boolean判断在调用 setValue 方法后是否立即引发 onChange 事件。
    tabIndex Integer当用户点击 tab 键在 widget 中切换时,可以通过此属性来设置 widget 获得焦点的顺序。
    方法 描述
    focus在 widget 上设置 focus
    getValue获得 widget 的值
    setValue设置 widget 的值
    reset重置 widget 的值为初始值
    undo恢复 widget 的值为之前最后一次更改的值

    表单 Widget 使用示例

    接下来,我们将通过一个网站注册表单案例的实现来介绍表单 widget 的使用方法。此案例的场景是一个电子商务类型网站的用户注册页面。表单的设计概要需求为:

    1. 表单结构为多步骤,需要给出清晰的导航
      • 使用进度标尺来告诉用户当前的位置和整个步骤
      • 强调几个步骤中的逻辑联系,比如标明:第一步、第二步、第三步等
    2. 表单的布局
      • 尽量使用对齐的字段、等长的输入框以及一致的视觉样式来减少视觉干扰
      • 尽量控制在一屏内出现 3-6 个字段或输入框
      • 标明选填和必填的差别
    3. 注册过程中的提示
      • 提示信息(tips)尽量在需要帮助的地方和时间出现
      • 填写表单时如有出错,即时显示提醒 / 警示信息,指引用户改正
      • 尽量避免出现弹出框的警示提醒

    这个注册页面设计成两步三屏组成:设置用户名和密码,填写个人资料,注册完成。这三屏由 Slider widget 作为进度标尺串联而成,下面分步介绍这些表单 widgets 。


    图 1
    图 1

    在由图 1 可以看到所需要填写的域有用户名、密码、设置密码保护问题、答案等。在处理表单提交的数据时,经常会碰到非法数据,此时就需要对数据的合法性进行校验。目前主流应用都会采用服务器端验证和客户端验证相结合的方案以兼顾网站安全性和用户友好性。 Dijit 的 TextBox 家族提供了 Validation, Currency, Number, Date, Time 等 Widgets 。可以说它们是标准 text 标签的功能加强版,在方便用户输入的同时,加强了数据的合法性校验能力。

    对于需要用户输入的文本域,ValidationTextBox widget 提供了强大的正则匹配功能,正好符合此需求;对于设置密码保护问题这一项,需要为用户提供备选项,同时又允许用户输入自己的希望输入的内容。本案例选择了用 ComboBox widget 来实现。所以在第一步中应用到了三类 widgets:Form widget,TextBox widget 和 ComboBox widget 。可以说这三个 widget 的用法都相对简单,下面来看一下它们用法。

    首先看 Form widget 的使用方法,清单 1 是实例化 Form widget 的代码。


    清单 1

    				
    <form
    dojoType="dijit.form.Form"
    id="registerForm"
    action="showPost.php"
    execute="showSteps(4);alert('Execute form w/values:\n'+dojo.toJson(arguments[0],true));"
    >

    从清单 1 中可以看到实例化 Form widget 首先要声明dojoType="dijit.form.Form" ,同时这里应用了 Form widget 的扩展点:execute 。这个扩展点就相当于 HTML 的 form 控件的事件 onSubmit,会在用户提交表单时执行一些 Javascript 方法。本案例中调用了一个方法 showSteps() 来显示完成页面,同时把用户填写的表单数据用 alert 的方式打印出来。

    设置好 Form widget 之后就需要向其中添加 ValidationTextBox widget 和 ComboBox widget,清单 2 是用户名、密码、确认密码、设置密码保护问题、答案等域的实现代码。


    清单 2

    				
    <div id="firststep">
    <div class="formSteps">
    <span>设置用户名和密码</span>
    </div>
    <div id="step1" class="formAnswer">
    <label class="firstLabel" for="name">用户名 *</label>
    <input type="text" id="name" name="name" class="medium"
    dojoType="dijit.form.ValidationTextBox"
    required="true"
    trim="true" invalidMessage="请输入用户名!"/>
    <br>

    <label class="firstLabel" for="password">密码 *</label>
    <input type="password" id="password" name="password" class="medium"
    dojoType="dijit.form.ValidationTextBox"
    required="true"
    regExp="[a-zA-Z]\w{5,17}"
    promptMessage="密码必须以字母开头,长度在6~18之间,并且只能包含字符、数字和下划线。"
    invalidMessage="请确认密码以字母开头,只能包含字符、数字和下划线,同时长度在6~18之间!"/>
    <br>

    <label class="firstLabel" for="validate">确认密码 *</label>
    <input type="password" id="validate" name="validate" class="medium"
    dojoType="dijit.form.ValidationTextBox"
    required="true"
    validator="return this.getValue() == dijit.byId('password').getValue()"
    invalidMessage="请确认两次输入密码一致!"/>
    <br>

    <label class="firstLabel" for="pwdquestion">设置密码保护问题 *</label>
    <select dojoType="dijit.form.ComboBox"
    value=""
    id="pwdquestion"
    autocomplete="true"
    hasDownArrow="true"
    >
    <option></option>
    <option>您的宠物名字是什么?</option>
    <option>北京奥运开幕式是哪天?</option>
    </select>
    <br />
    <label class="firstLabel" for="answer">答案 *</label>
    <input type="text" id="answer" name="answer" class="medium"
    dojoType="dijit.form.ValidationTextBox"
    required="true"
    trim="true" invalidMessage="请输入答案!"/>
    <br>
    </div>

    <center>
    <button
    dojoType="dijit.form.Button"
    οnclick="showSteps(2)"
    iconClass="dijitEditorIcon
    dijitEditorIconSave"
    type=button>
    下一步
    </button>
    </center>
    </div>

    在清单 2 中有四处用到了 ValidationTextBox widget,其中用户名和答案这个两个文本域的验证相对简单,只是通过属性required="true" 来设置此域是必须填写的。同时通过设置属性 invalidMessage 来设置错误提示信息。不过请读者注意,这里的只是做了一个简单的 Demo,以演示 Widgets 的用法。在实际应用中应需要从客户端和服务器端两方面对用户名等表单数据的合法性进行校验。

    下图是用户没有填写用户名时,显示的错误提示信息。错误提示信息会以 Dijit 的一个高级 widget - Tooltip 为载体显示出来,开发人员可以通过 ValidationTextBox widget 的属性 tooltipPosition[] 来设置 Tooltip 显示的位置,关于 Tooltip 的用法会在本文第四部分:高级 Widget 的使用中介绍。


    图 2
    图 2

    看到这里,有的读者可能会问,难道 ValidationTextBox widget 就只能设置文本域是否必填么?不是的,它还有更炫的利用正则匹配进行验证的机制。通过密码和确认密码这两个文本域的应用可以初步了解 ValidationTextBox widget 相对高级的验证方式。

    ValidationTextBox widget 一般采用正则表达式来验证,利用正则表达式强大的匹配功能,可以说 ValidationTextBox widget 可以满足目前各种常用输入域的格式要求。比如 IP 地址的验证,URL 的验证,Email 地址的验证,密码格式的验证等等。清单 2 中密码输入域的验证就是采用了正则表达式匹配验证。

    ValidationTextBox widget 提供了两种引用正则表达式的方式:直接引用和通过调用方法返回正则表达式的方式引用。在清单 2 中 ID 为 password 的 ValidationTextBox widget 采用的是第一种引用正则表达式的方式:直接设置属性 regExp 的值为正则表达式,如regExp="[a-zA-Z]\w{5,17}" 。这里的正则表达式要匹配的是以字母开头([a-zA-Z] ),后接 4 到 16 个任意单一字符(\w 表示任意单一字符 , 同 [a-zA-Z0-9])。 ValidationTextBox 另外一种方式:设置属性 regExpGen 的值为返回正则表达式的方法名,如regExpGen="dojox.regexp.emailAddress" 。方法 dojox.regexp.emailAddress 中提供了域名列表,更明确的限制了域名的合法性。建议简单的验证可以选择设置regExp 属性,而较为复杂的验证选择设置regExpGen 属性,这样可以提供较为复杂的正则表达式组合。

    与用户名输入域相比,密码输入域还增加了一个方法:promptMessage 。这是 ValidationTextBoxes widget 获得焦点时弹出的辅助提示信息,而 invalidMessage 是在用户输入不合法时的即时提示。图 3 是这两种提示信息的比较图。当密码输入域获得焦点时,会弹出辅助提示信息:密码必须以字母开头,长度在 6~18 之间,并且只能包含字符、数字和下划线。此时输入域处在编辑的状态,并且颜色没有改变。当用户进行输入未符合要求时,会弹出错误提示信息:请确认密码以字母开头,只能包含字符、数字和下划线,同时长度在 6~18 之间!此时输入域为黄色,并且在输入框末尾有警示图标。


    图 3
    图 3

    另外在第一步中还有一个 widget:ComboBox 。可以说 ComboBox widget 一个自动完成、辅助用户输入的文本输入域。它是 [select] 组合框和 [text] 输入域的结合体:既可以像 [select] 组合框那样提供一列可选值,也可以像在 [text] 输入域里那样输入用户想要输入的任何值。首先来了解一下 ComboBox widget 的属性:


    表 2. dijit.form.ComboBox 的属性列表

    属性 属性类别 描述
    autoCompleteBoolean
    true
    判断是否自动完成用户输入的内容。当值为真时,用户输入部分字符串,ComboBox widget 会把能匹配上的可选值列出,如果光标离开此 widget,会显示第一个匹配的选项值。
    hasDownArrowBoolean
    true
    判断是否现实下拉按钮。
    ignoreCaseBoolean
    true
    判断是否忽略大小写(针对英文的输入)。
    pageSizeInteger
    Infinity
    此属性可以设置下拉列表显示的条数,如果出现多页的情况,会在下拉列表中显示” Previous choices ”和” More choices ”按钮。用户可以通过点击这两个按钮来查找选项。
    queryObject
    {}
    设置查询表达式以过滤’ store ’里的选项。
    searchAttrString
    name
    设置查找的匹配表达式
    searchDelayboolean
    true
    当用户输入内容后到 Dojo 开始查找用户输入值的匹配项之间的间隔时间。
    storeObject数据提供对象的一个引用。 .Dijit 中一般应用 JSON 格式的数据。

    清单 2 中的 ComboBox widget 实例用到了两个属性 autoComplete 和 hasDownArrow 。这两个属性已经表 2 中介绍过了,这里不再多说。 ComboBox widget 的另一亮点就是可以从外部文件动态加载选项,并且提供了属性来过滤选项,同时可以设置下拉列表每页显示选项的数量。

    第一步就讲到这里,下面来看一下第二页中用到的 widgets 。


    图 4
    图 4

    在图 4 中可以看到需要填写的项为:真实姓名、邮编、手机号。在这里仍然选择 ValidationTextBox widget 。性别项为单选项,本例选择了 RadioButton widget 。出生日期项需要用户按照 MM/DD/YYYY 的格式输入日期,以往 Web 开发人员可能会需要写大段的 JS 代码来实现一个日期控件,并且还要写一堆日期格式的验证代码。现在 Dijit 提供了一个 DateTextBox widget,一行代码搞定所有的工作。对于“省”这一项,选择的是 FilteringSelect widget 。可以说 FilteringSelect 跟 ComboBox 非常类似,不过 FilteringSelect 不允许用户输入可选项之外的值。因为市名特别多,并且不易收集完整,所以这个 Demo 中选择使用了 ComboBox widget 来实现。在给出用户一定的可选项的同时,允许用户自己输入。最后同意条款的复选框理所当然的选择了 CheckBox widget 。

    由于在第一步中已经介绍过 ValidationTextBox widget,这里不再赘述。 RadioButton widget 和 CheckBox widget 同属于 Button 类型的 widget,其使用非常方便:只需要在 HTML 标准的 checkbox / radio 控件上加上 dojoType 的属性,值是” dijit.form.CheckBox ”或者” dijit.form.RadioButton ”。此处要注意的是声明 dojoType 时,大小写敏感。清单 3 中图 4 中使用 CheckBox widget 的代码示例:


    清单 3

    				
    <input
    type="checkBox"
    name="agreement"
    id="ag"
    value="ag"
    dojoType="dijit.form.CheckBox" />
    <label for="ag">我同意并接受以下条款</label>

    当 Dojo 解析到控件的属性 dojoType 为 dijit.form.CheckBox 时,会应用 dijit.form.CheckBox 中定义的 templateString(清单 4)替换掉源代码中 [checkbox] 的定义增加了一些属性和方法,然后输出到页面(清单 5)。


    清单 4

    				
    <div
    class=\"dijitReset dijitInline\"
    waiRole=\"presentation\"\n\t>

    <input\n\t \t
    type=\"${type}\"
    name=\"${name}\"\n\t\t
    class=\"dijitReset dijitCheckBoxInput\"\n\t\t
    dojoAttachPoint=\"focusNode\"\n\t \t
    dojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onclick:_onClick\"\n/>
    </div>\n



    清单 5

    				
    <div
    wairole="presentation"
    class="dijitReset dijitInline dijitCheckBox"
    role="wairole:presentation"
    widgetid="ag">
    <input
    type="checkbox"
    dojoattachevent="onmouseover:_onMouse,onmouseout:_onMouse,onclick:_onClick"
    dojoattachpoint="focusNode"
    class="dijitReset dijitCheckBoxInput"
    name="agreement"
    id="ag"
    value="ag"
    tabindex="0"
    style="-moz-user-select: none;"
    pressed="false"/>
    </div>

    由清单 4 和清单 5 可以看出,Dojo 接管了标准 [checkbox] 控件的三个事件:onmouseover,onmouseout 和 onclick 。分别代替为 _onMouse 和 _onClick,以此更改 Checkbox 的表现形式。

    提示:

    如果有兴趣可以在文件 _FormWidget.js 中找到 _onMouse 方法的定义,在 Button.js 文件中找到 _onClick 方法的定义。


    图 5
    图 5

    图 5 是完成页面的截图,非常简单,只显示了注册完成的提示信息。不过这步让包括了一个我们还没有介绍的 widget:Slider widget 。其实 Slider 贯穿了三步,在每屏都会显示注册的进度,可以说是表单 Widget 中比较独特的一个,下面详细介绍了 Slider Widget 的使用。

    Slider Widget 的使用

    与 CheckBox widget 相比,Slider widget 较为复杂,至少在标准的 HTML 标签库中是没有 Slider 控件的。 Slider widget 的使用却如同使用 CheckBox widget 一样的方便。用户可以用鼠标点击、拖拉、中键滚动或者用键盘的上、下、左、右按键来选择 Slider widget 的刻度。

    Silder 是由六个 widgets 组成,分别是:dijit.form.HorizontalSlider, dijit.form.VerticalSlider,dijit.form.HorizontalRule, dijit.form.VerticalRule,dijit.form.HorizontalRuleLabels, dijit.form.VerticalRuleLabels 。这里可以“望文生义”一下:从 widgets 的名字可以看出 dijit.form.HorizontalSlider, dijit.form.VerticalSlider 分别是水平方向和垂直方向的 slider,提供可调节大小的标尺。其属性如下表:


    表 3. HorizontalSlider 和 VerticalSlider 的属性

    属性 属性类别 描述
    clickSelectboolean
    true
    判断是否可以点击进度条来更改刻度值
    discreteValuesinteger
    Infinity
    在最大值与最小值之间可以设置的最大值
    intermediateChangesBoolean
    false
    判断在调用 setValue 方法时是否直接触发 onChange 事件。如果为’ true ’,则每次执行 setValue 方法时都会触发 onChange 事件;如果为’ false ’,则 onChange 事件只有在自己被调用时才会被触发。
    maximuminteger
    100
    可设置的最大刻度值
    minimuminteger
    0
    可设置的最小刻度值
    pageIncrementinteger
    2
    点击键盘按键 pageup/pagedown时一次变化的刻度值
    showButtonsboolean
    true
    判断是否在刻度条两端显示增加和减小的按钮

    dijit.form.HorizontalRule, dijit.form.VerticalRule 可以为 HorizontalSlider 和 VerticalSlider 设置标识线,其属性如下:


    表 4. HorizontalRule 和 VerticalRule 的属性

    属性 属性类别 描述
    containerNode
    containerNode
    设置要连接的父节点
    countInteger
    3
    标识线的数量
    ruleStyleString为个别标识线设置 CSS style

    当在页面中有多个 dijit.form.HorizontalRule widgets 时,通过设置 container 值来区分他们,比如清单 6 中第一个 dijit.form.HorizontalRule widget 设置container="topDecoration" ,而第二个设置container="bottomDecoration" 。这样用户就可以看到在标尺的上下两方各有一组标识线。同时设置属性 count 的值来确定标识线的个数,譬如清单 6 中第一个 dijit.form.HorizontalRule widget 的 count 的值为 6,则在标尺上方会有六个标识线,每两个标识线间距是总长的 1/5 。

    dijit.form.HorizontalRuleLabels, dijit.form.VerticalRuleLabels 可以为标尺提供刻度标签,其属性如下:


    表 5. HorizontalRuleLabels 和 VerticalRuleLabels 的属性

    属性 属性类别 描述
    labelsArray
    []
    文本类型的数组,存放要展现的标签值
    labelStyleString为个别标签设置 CSS style

    dijit.form.HorizontalRuleLabels 是继承 dijit.form.HorizontalRule,所以 RuleLabels 类型的 widgets 都具有 Rule 类型 widgets 的属性,同时也有自己特有的属性。通过 labels 属性,开发人员可以随心设置刻度标签的值。

    Dijit 提供了两种方式来设置标签值,第一种就是直接设置 labels 属性的值为一数组或者返回数组的 Javascript 方法;第二种方式就是在页面标记为 dijit.form.HorizontalRuleLabels 的标签内部设置 <li>,这也正是清单 6 中采用的方式。当 labels 属性值为空时,Slider 会自动搜索本节点内部的 <li> 标签,取出 <li> 标签节点的 innerHTML 作为单个标签值。

    下面通过实例来看 Slider widget 的使用。


    清单 6

    				<html> 
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Dijit HorizontalSlider Example</title>
    <style type="text/css">
    @import "dojoPath/dijit/themes/tundra/tundra.css";
    @import " dojoPath/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="dojoPath/dojo/dojo.js"
    djConfig="parseOnLoad: true"></script>
    <script type="text/javascript">
    dojo.require("dojo.parser");
    dojo.require("dijit.form.Slider");
    </script>
    </head>
    <body class="tundra">
    <div id="horizontalSlider" dojoType="dijit.form.HorizontalSlider"
    onChange="dojo.byId('sliderinput').value=dojo.number.format(arguments[0]/100,{places:1,
    pattern:'#%'});" handleSrc=
    "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/images/preciseSliderThumb.png"
    value="10" minimum="0" maximum="100" discreteValues="100" intermediateChanges="true"
    showButtons="true" style="width:50%;">

    <ol dojoType="dijit.form.HorizontalRuleLabels" container="topDecoration"
    style="height:1em;font-size:75%;color:gray;">
    <li> </li>
    <li>20%</li>
    <li>40%</li>
    <li>60%</li>
    <li>80%</li>
    <li> </li>
    </ol>

    <div dojoType="dijit.form.HorizontalRule" container="topDecoration" count=6
    style="height:5px;" ></div>
    <div dojoType="dijit.form.HorizontalRule" container="bottomDecoration" count=3
    style="height:5px;" ></div>

    <ol dojoType="dijit.form.HorizontalRuleLabels" container="bottomDecoration"
    style="height:1em;font-size:75%;color:gray;">
    <li>0%</li>
    <li>50%</li>
    <li>100%</li>
    </ol>
    </div>
    Slider Value:<input readonly id="sliderinput" size="4" value="10.0%">
    </body>
    </html>

    在清单 6 中可以看到 Slider,Rule,RuleLabels 的应用。 dijit.form.HorizontalSlider 是把 dojoType 属性设置在’ DIV ’标签内的,由于intermediateChanges="true" ,onChange 事件会在调用 setValue 方法时自动触发。这里设置的 onChange 事件是更新 id 为’ sliderinput ’的一个只读域的值,效果如图 6 所示。在实际项目中 Slider widgets 可以应用到多个模块中,比如图片的浏览和缩放,多页面间的转换,文本长度的控制等等。


    图 6
    图 6




    回页首


    布局 Widget 的使用

    Web 应用的页面布局一直是令 web 开发者头疼的一件事情。在 Web 2.0 的时代,Web 页面布局的设计越来越多样化,仅仅依靠 Tables 和 CSS 控制的页面布局已难满足用户的需求。为此 Dijit 提供了一系列的布局 Widgets 辅助 Web 开发人员实现复杂的页面布局。

    布局 Widget 简介

    首先来浏览一下布局 Widgets 的成员。 Dijit 中提供的布局 Widgets 可以分为三类:

    • 对齐方式容器:用以盛放屏面类 widgets,并且可以设置这些 widgets 的排列方式。这类的布局 Widgets 有 BorderContainer,LayoutContainer,SplitContainer 。其中 BorderContainer 是在 Dojo1.1 中引进的轻量级组件,有取代 LayoutContainer,SplitContainer widgets 之势。目前 Dojo 不推荐使用 LayoutContainer,SplitContainer widgets ;
    • 堆叠容器:此类的 widgets 可以把前两种 widgets 层叠在一起,而一次只显示一个屏面。这类的的布局 Widgets 有 AccordionContainer,TabContainer,StackContainer 等。
    • 屏面:盛放和显示大块的内容,包括文本、图片、图表,甚至是其它 widgets 。这类的布局 Widgets 有 ContentPane 等;

    在设计页面布局时,首先应选择页面整体的框架:上下两栏、左右两栏、上中下三栏、左中右三栏、上一栏下两栏、上下左右中五栏等。在以往的 Div + CSS 设计布局时,虽然可以轻松得做到前五种布局的实现,但如果要实现最后一种五栏的布局,却有些困难。并且设计后的布局间的比例或者每栏的大小都是固定的,当一栏的内容超出栏宽 / 高时,只能通过左右拉条或者下拉条的拖动来显示超出的内容。可以说既麻烦又不美观。

    在 Dijit 的布局 widgets 中,对齐方式容器类的 BorderContainer widget 提供了一套简单的 API,可以在页面中设置上下左右中五栏的内容 ―― 也就是设置屏面的内容,甚至可以嵌套设计。同时在每两个相邻的屏面间有一分割的组件,可以调节屏面的大小。

    为解决页面内容多,导致出现左右或者上下拖动条的情况,Dijit 提供了堆叠类容器。无论是 AccordionContainer,TabContainer,还是 StackContainer 它们实现的功能是一样的:把内容分成多个屏面,每次只显示一屏的内容,要想显示其它屏的内容,需要点击那屏的标题栏。

    如果说前面这两类布局 widgets 为页面提供了骨架和骨骼的话,那么屏面类 widgets 就是填充这些骨架的真材实料。下面简单介绍这三类布局 widgets 的属性、方法以及用法等。

    BorderContainer widget

    首先介绍页面的骨架:对齐方式容器。前面已经说过 LayoutContainer 和 SplitContainer widgets 在 Dojo1.1 中被标注为不推荐使用,所以此类 widget 首推 BorderContainer 。可以说 BorderContainer 是 LayoutContainer 的升级版,同时集成了 SplitContainer 优点:为用户提供可拖动的边界。

    像之前提过的那样,BorderContainer 可以向五个区域输出:上下左右中。同时这五个区域也有两种不同的摆设,可以通过属性 design 来设置。如果 design 为“ headline ”,上下两个区域的宽度就会与 BorderContainer 的宽度相同;如果 design 为“ sidebar ”,左右两个区域的高度就会和 BorderContainer 的高度相同。下面是这两种设计形式的示意图,其中第一张图片的 design 属性为“ headline ”。


    图 7 design 属性分别为“headline”和“sidebar”的 BorderContainer 示意图
    图 7 design 属性分别为“headline”和“sidebar”的 BorderContainer 示意图图 7 design 属性分别为“headline”和“sidebar”的 BorderContainer 示意图

    清单 7 是图 7 中 design 属性值为“ headline ”的实现代码,直接更改 design 属性值为” sidebar ”就可以实现第二张图的效果。同时从清单 7 中还可以注意到


    清单 7

    				
    <style type="text/css">
    html, body, #main{
    width: 100%; /* make the body expand to fill the visible window */
    height: 100%;
    }
    </style>

    <div dojoType="dijit.layout.BorderContainer" design="headline" id="main">
    <div dojoType="dijit.layout.ContentPane" region="leading"
    splitter="true" style="background-color: #acb386; width: 100px;">
    leading
    </div>
    <div dojoType="dijit.layout.ContentPane" region="top"
    style="background-color: #b39b86; height: 100px;">
    top bar
    </div>
    <div dojoType="dijit.layout.ContentPane" region="center"
    style="background-color: #f5ffbf; padding: 10px;">
    main panel
    </div>
    <div dojoType="dijit.layout.ContentPane" region="bottom"
    style="background-color: #b39b86; height: 100px;" splitter="true">
    bottom bar
    </div>
    <div dojoType="dijit.layout.ContentPane" region="trailing"
    style="background-color: #acb386; width: 100px;" splitter="true">
    trailing
    </div>
    </div>

    通过清单 7 也可以看到样式的定义中设置了属性 width 和 height,这里也是要注意的地方:BorderContainer 节点需要设置 width 和 height 。同时左右两个子节点可以设置宽度,而上下两个子节点可以设置高度。中间区域的子节点无需设置大小,刨去四个边界区域占有的空间,剩下的就是中间区域。

    当需要调节区域大小时,spliter 属性就派上用场了。当开发人员希望用户可以自己调节屏面大小时,可以设置此属性值为“ true ”。这样在两屏面间就会出现一个可以拖拽的边界。同时如果开发人员不希望用户自己调节屏面大小,就可以设置此属性为“ false ”。

    TabContainer widget

    当一个页面内容较多,而用户不希望像看十米长卷一样一直向下托动滚动条来浏览页面时,应用堆叠容器 widgets 是一个比较不错的选择。将功能类似的一些信息放在同一个标签页内,用户可以方便的在不同的标签页之间切换,并且可以关闭不想要的标签页。 AccordionContainer,TabContainer,StackContaine 三个 widgets 实现的功能相同,只是表现形式不同,这里通过 TabContainer 的介绍来了解一下堆叠容器 widgets 的使用。

    首先看一下实现一个 TabContainer 所需要的元素。 TabContainer 实现的功能就是包含多个内容面,而一次只显示一个。为了可以选择用户需要的内容面,就需要为每一个内容面配备一个标签。就像平时自己整理文档一样,每个标签上面都有标题来标注此类文档的用途。在现实生活中,有时候不需要某份文档了,就会把此文档粉碎。为模仿此操作就需要为每个标签配备一个关闭按钮(可选的)。那好,到目前为止构建一个 TabContainer 所需的元素凑齐了:内容面,标签,关闭按钮。那剩下来就是技术活:关联这三个元素,TabContainer 已经为开发者做好了这项工作,开发人员所需要的就是创建 TabContainer 和需要的 ContentPane 。下面来看一代码片段:


    清单 8

    				
    <div id="mainTabContainer" dojoType="dijit.layout.TabContainer"
    style="width:500px;height:100px">
    <div id="FirstPane" dojoType="dijit.layout.ContentPane" selected="true"
    title="The first pane">
    The first pane. Can put text,picture or dialog here!
    </div>
    <div id="SecondPane" dojoType="dijit.layout.ContentPane"
    title="The second pane" closable="true">
    The second pane! You can close me, Cool ha!
    </div>
    </div>

    在清单 8 中的代码片断是一个简单的 TabContainer 例子,声明了一个 TabContainer widget 和两个 ContentPane widget 。其中 TabContainer 的声明很方便,直接设置dojoType="dijit.layout.TabContainer" 就可以,省下来的工作就是声明 ContentPane 。 ContentPane widget 会有一些特殊的属性,比如closable="true" 。这是标签是否附带关闭按钮的标示,如果为“ true ”则标签上会显示关闭按钮。同时标签的内容是通过 title 属性来设置的,图 8 是清单 8 在浏览器中的输出。


    图 8 TabContainer 示例效果图
    图 8 TabContainer 示例效果图

    如果希望不同的标签显示的是单独的页面文件时,可以设置 dijit.layout.ContentPane 的属性 href 。譬如<div id=" Third Pane" dojoType="dijit.layout.ContentPane" href= " test.html " title="The third pane">

    ContentPane widget

    ContentPane 是所有布局 widgets 的基石,其他的任何一个布局 widgets 都可以用 ContentPane 作为内容或者子 widget 的载体。同时 ContentPane 也可以单独使用,可以盛放文本、图片、图表,甚至其它 widgets 。首先看一下 ContentPane wdiget 的属性和方法。


    表 6.ContentPane widget 的属性列表

    属性 属性类别 描述
    errorMessageString
    Locale dep.
    错误提示信息,可以在 loading.js 文件中更改默认信息。
    extractContentBoolean
    false
    当取回的内容是页面时,判断是否抽取页面标签 <body> … <//body> 内的可见的内容。
    hrefString当前实现内容的超链接。如果在构造 ContentPane widget 的时候设置此项,就可以在 widget 显示的时候加载数据。
    isLoadedBoolean
    false
    设置加载状态。
    loadingMessageString
    Locale dep.
    加载时显示的信息,同 errorMessage 一样可以在 loading.js 文件中更改默认信息。
    parseOnLoadBoolean
    true
    解析取回的内容,如果有 widgets 的声明,会实例化 widgets 。
    preloadBoolean
    false
    强制加载数据。
    preventCacheBoolean
    false
    判断是否缓存取回的外部数据。
    refreshOnShowBoolean
    false
    在本 widget 从隐藏到展现时,判断是否刷新数据。



    表 7.ContentPane widget 的方法列表

    方法 描述
    cancel()取消进行中的内容下载
    refresh()强制刷新
    resize(/* String */size)此方法可以重新设置 widget 的大小。
    setContent(/*String|DomNode|Nodelist*/data)代替原有的内容,替换为新的内容。这个方法经常用到,可以动态向 ContentPane 中输入其它 widgets 。
    setHref(/*String|Uri*/ href)替换原有的超链接,通过 XHR 的形式异步获取数据,然后重置此 widget 中的内容。

    表 6 中列出的都是 ContentPane 作为一个单独的 widget 使用时的属性。如果把 ContentPane 作为其它布局 widgets 的子节点,就需要为不同的布局 widget 增加不同的属性。譬如在清单 7 中的region="top" 和清单 8 中的closable="true" 等。

    布局 Widget 使用示例

    这部分通过一个简单的页面布局示例把这三中布局 widgets 串连在一起。示例的需求是这样的:一个页面需要分为四个区域,上下左和中;头部为页面标题,左侧为导航栏,底部为另外一个导航栏,中间部分显示详细信息。图 9 本示例的效果图。


    图 9 布局 Widget 示例效果图
    图 9 布局 Widget 示例效果图

    为把页面分为四部分,需要采用 BorderContainer widget 。设置其属性 design 为“ headline ”,同时创建 4 个子节点,属性 rigion 分别为“ left ”“ top ”“ buttom ”“ center ”。其中左侧栏为导航栏,选择 AccordionContainer ;上栏只是显示标题,所以直接安放一个 ContentPane ;底部也是一个导航栏,这里选择 TabContainer 来实现;中间部分显示左侧导航栏的详细信息,选择 ContentPane 。那么这些 widgets 的层次关系就如下面的列表:

      • BorderContainer ;
        • Top Border Container
          • ContentPane #1
        • Left Border Container
          • Accordion Container
            • ContentPane #2
            • ContentPane #3
            • ContentPane #4
        • Right Border Container
          • ContentPane #5
        • Bottom Border Container
          • Tab Container
            • ContentPane #6
            • ContentPane #7

    根据这些 widgets 的层次关系就很容易创建这个页面的布局。清单 9 是本示例的实现代码:


    清单 9

    				
    <style type="text/css">
    html, body, #main{
    width: 100%; /* make the body expand to fill the visible window */
    height: 100%;
    overflow: hidden; /* erase window level scrollbars */
    padding: 0 0 0 0;
    margin: 0 0 0 0;
    font: 10pt Arial,Myriad,Tahoma,Verdana,sans-serif;
    }
    </style>
    <div dojoType="dijit.layout.BorderContainer" design="headline" id="main">
    <div dojoType="dijit.layout.AccordionContainer" duration="200"
    region="left" style="background-color: #acb386; width: 400px;" splitter="true"
    style="float: left; width: 400px; height: 300px; overflow: hidden">
    <div dojoType="dijit.layout.AccordionPane"
    title="First pane of AccordionContainer">
    <p><a href="#">the first link</a><br />
    <a href="#">the second link</a><br />
    <a href="#">the third link</a></p>
    </div>
    <div dojoType="dijit.layout.AccordionPane"
    title="Second pane of AccordionContainer">
    <p> <a href="#">the first link</a><br />
    <a href="#">the second link</a><br />
    <a href="#">the third link</a></p>
    </div>
    <div dojoType="dijit.layout.AccordionPane"
    title="Third pane of AccordionContainer">
    <p> <a href="#">the first link</a><br />
    <a href="#">the second link</a><br />
    <a href="#">the third link</a></p>
    </div>
    </div>

    <div dojoType="dijit.layout.ContentPane" region="top"
    style="background-color: #ACBFD0; height: 100px;">
    <h1>Page Title</h1>
    </div>

    <div dojoType="dijit.layout.ContentPane" region="bottom"
    style="background-color: #ACBFD0; height: 200px;" splitter="true">
    <div id="mainTabContainer" dojoType="dijit.layout.TabContainer"
    style="width: 100%; height: 20em;">
    <div id="tab1" dojoType="dijit.layout.ContentPane" href="tab1.html" title="Tab 1">
    </div>
    <div id="tab2" dojoType="dijit.layout.ContentPane" href="tab2.html"
    refreshOnShow="true" title="Tab 2" selected="true"></div>
    </div>
    </div>

    <div dojoType="dijit.layout.ContentPane" region="center"
    style="background-color: #f5ffbf; padding: 10px;">
    main panel to display different contents according to the selected pane of left bar.
    </div>
    </div>





    回页首


    高级 Widget 的使用

    本部分会简单介绍一下高级 Widget 的使用。

    高级 Widget 简介

    Dijit 在提供一些基本的 widgets 的同时也提供了一些高级功能的 widgets 。比如说 Editor,ProgressBar,Tooltip,ColorPaletee,Tree,Dialog 等。这里把这些高级 widgets 分为两类:用户辅助 Widget,高级编辑和显示 Widget。

    用户辅助 Widget 包括:

    • Dialog:相对应于 HTML 的对话框,是一个模式对话框。用户能通过此 widget 上的关闭按钮关闭此对话框,同时也可以在此对话框上放置表单 widgets,并且可以在此对话框上直接提交表单;
    • TooltipDialog:此 widget 必须关联一个 DropDownButton 。用户点击 DropDownButton 时,此对话框显示,用户点击此对话框外任何位置都可以让此对话框消失;
    • ProgressBar:Dijit 提供的进度条组件;
    • Tooltip:此 widget 的表现形式类似于属性 title,功能却很远比属性 title 强大。弹出的提示窗口中可以显示文本、图片和页面。同时可以设置提示窗口出现的位置,之后会详细介绍 Tooltip 。

    高级编辑和显示 Widget 包括:

    • ColorPalette:一个颜色选择组件,为用户提供一组可供选择的颜色块。可以跟页面背景或者局部区域颜色关联起来。通过属性 palette 来设置可供选择的颜色块的数量,目前提供 "7x10" 和 "3x4" 两种选择。
    • Editor:一个多文本的编辑器组件,外观类似于 word 编辑器。提供了一系列的编辑按钮,包括拷贝、粘贴、撤销、各种字体处理、数字编号或者项目符号,文本对齐格式等等。值得一提的是这个组件的架构是插件架构,支持开发人员自己开发新的命令、按钮等。
    • InlineEditBox:类似于 Dojo 0.9 中的 dijit.form.InlineEditBox widget 。可以编辑页面显示的输出类型文本,当点击文本时,文本就会从浏览状态转换为可编辑状态。
    • Tree:此组件可以把有层次关系的数据用树状结构展现出来,就如同 Windows 系统的资源浏览器。

    下面通过 Tooltip 的介绍来帮助读者认识高级 Widget 的使用。

    Tooltip Widget 的使用

    目前大多数应用中,每个页面的控件都比较多,而仅仅通过控件显示的名称是不足以让用户了解各种控件的作用和一组相同类型控件间的区别。标准的 HTML 控件会提供 title 属性。当用户鼠标停留在设置好 title 属性值的控件上时,浏览器会弹出一个提示,内容就是属性 title 的值。

    但是 title 属性有自己的不足之处,比如样式单一,只能显示文本,长文本在 Firefox 中不能完全显示等等。所以有不少开发人员自己动手创建自定义的提示工具。其中有的方案是把提示信息放在层标签中,在 onmouseOver 事件中调用显示层标签的方法,在 onmouseOut 事件中调用隐藏层标签的方法,以达到模仿 title 属性的目的;同时也有方案在页面初始化的时候收集所有设置了 title 属性的控件,取到 title 的值,经过一定的处理显示在自定义的提示框中。

    Dojo 提供了一个更美观,实用的辅助提示 widget:Dijit.Tooltip 。其样式定义在单独的样式文件中,开发人员可以自己修改。同时也提供了一些强大的功能,比如可以显示图片、图表和从服务器请求得到的数据等,可以控制显示的时间和出现持续的时间。

    实例化 Tooltip 的方法有多种,除了所有 widget 都具备的declarativelyprogrammatically 方式外,还可以调用 Dijit 提供的方法dijit.showTooltip(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position) 显示 Tooltip,调用dijit.hideTooltip = function(aroundNode) 来隐藏 Tooltip 。在后面的实例中会涉及到这三种方法。

    在看实例之前可以先浏览一下 Tooltip 的属性:


    表 8. dijit.Tooltip 的属性

    属性 属性类别 描述
    connectIdString要挂载 Tooltip 的控件的 Id,可以为用逗号分隔的多个 Id 。
    labelString要显示的提示信息
    showDelayInteger
    400
    Tooltip 显示之前等待的时间,毫秒级



    清单 10

    				
    <script type="text/javascript" src="dojo/dojo.js"
    djConfig="parseOnLoad: true"></script>
    <script type="text/javascript">
    dojo.require("dojo.parser");
    dojo.require("dijit.Tooltip");

    var prTooltip = new dijit.Tooltip( {label:'This tooltip is instantiated in
    programmatically way',connectId:'programmatically'}, document.createElement('div'));

    function showTooltip(labelText, nodeId, position){
    dijit.showTooltip(labelText, dojo.byId(nodeId),position);
    }
    function hideTooltip(nodeId){
    dijit.showTooltip(dojo.byId(nodeId));
    }
    </script>

    <div dojoType="dijit.Tooltip" connectId="declaratively"
    label="This tooltip is instantiated in declaratively way"> </div>
    <div id="declaratively">Declaratively</div>
    <br />
    <div id="programmatically">Programmatically</div>
    <br />
    <div id="callMethods" onmouseOver="javascript:showTooltip('This tooltip
    is instantiated in calling method way','callMethods',['after','before']);"
    onmouseOut="javascript:hideTooltip('callMethods');">Calling Methods</div>

    在清单 10 中分别应用了三种实例化的方法。 Declaratively 方式实例化 Tooltip 时除了要声明 dojoType 为 dijit.Tooltip,还要设置另外两个特殊的属性:connectId 和 label 。如表 4 所示,属性 connectId 的值是要关联 Tooltip 的控件 Id,属性 label 的值为提示信息的内容。

    Programmatically 方式实例化 Tooltip 如var prTooltip = new dijit.Tooltip( {label:'programmatically',connectId:'programmatically'}, document.createElement('div')); 第一个参数是 Tooltip 特殊的属性值:label,connected,positions 等;第二个参数是要实例化的控件,可以创建一个新的控件,也可以应用已存在的控件(用 dojo.byId(someId) 来定位要实例化为 Tooltip 的控件)。

    有时候页面需要实例化的 Tooltip 非常多,曾经遇见过一个数据报表页面有五百多个链接要挂载 Tooltip !这时无论用 Declaratively 方式还是Programmatically 方式都会导致页面数据量猛增,达到 MB 级,在 web 应用中这是不可以接受的。在这种情况下选用第三种实例化的方式可以在很大程度上减少页面的大小。



    html>
    展开全文
  • 掌握 Dojo 工具包,第 5 部分: Dojo 的 UI 组件库 - Dijit 这一期的 掌握 Dojo 系列 文章将主要讲述 Dojo 工具包的 UI 组件库 - Dijit 中类型多样的 Widget 及其使用方法。 查看本系列更多内容 | ...
  • Dojo 0.9 开始,Dojo 把 Widget 从 Dojo 的核心包中分离出来,组成 Dijit 。 Dojo 在 Dijit 中为 Widget 家族添加了多位成员,增强了 Widget 的实力的同时也加快了其在页面中的加载速度。 为改善 Widget 的...
  • dojo

    2011-02-24 11:23:00
    Dojo 日期控件的国际化和集成 黄 腾龙 (huangtl@cn.ibm.com), 软件工程师, IBM 黄腾龙,软件工程师,目前在 IBM 中国软件开发中心工作。对 J2EE 应用程序开发,软件过程及自动化测试有着浓厚的兴趣。 赵 迎威 ...
  • Dojo

    千次阅读 2011-12-29 11:49:44
    Dojo 体系架构 Dojo 是一个分层的体系架构。最下面的一层是包系统,Dojo API 的结构与 Java 很类似,它把所有的 API 分成不同的包(package),当您要使用某个 API 时,只需导入这个 API 所在的包。包系统上面一层...
  • 这是两个封装良好的日历组件,用来给用户提供方便的日历选择方式。...//-->然后在页面中加入:或Dojo就会自动生成两个日历组件,一个用来选择开始日期,一个用来选择结束日期。其 中的属性dojoType指明w
  • Dijit 是 Dojo 工具包的富组件用户界面库。这些组件完全可以主题化,并且可以通过两种方式声明:可以使用 HTML 风格的标签以声明式方法声明,也可利用 JavaScript 以编程方式声明。这一部分将简要介绍 Dijit,介绍它...
  • Dojo 进阶

    2019-10-14 21:30:44
    官网 https://dojo.io 序言 - 构建企业级 web 应用程序 在热衷敏捷交付的时代,鼓励将小功能点持续地交付给用户。软件行业开始青睐这种方式,因为它最大限度地降低风险,并最大限度地提高用户的参与度和满意度。 ...
  • my dojo your dojo

    2014-04-07 20:01:02
    随着富互联网应用程序(Rich Internet Application,RIA)的发展,一批 JavaScript Toolkit 也随之兴起 , Dojo 便是其中的优秀代表,本文 将由浅入深带领读者走进 Dojo 的世界。本文作为这个系列的开篇 , ...
  • DOJO】初识Dojo

    2019-09-29 23:57:29
    定义 Dojo是一个用JavaScript语言实现的开源DHTML工具包。它是在几个项目捐助基础上建立起来的(nWidgets,Burstlib, f(m)),这也是为什么叫它a u...
  • Dojo 工具包提供了大量的特性,这些特性节省了 Web 应用程序开发人员开发时间和工作量,使他们能够创造丰富的 Internet 应用程序。从 DOM helper 和 Ajax 到完善的 widget 库和面向对象的特性,Dojo 实际上包括您...
  • 掌握 Dojo 工具包

    2015-06-13 10:12:33
    其中 Dojo 是核心功能包 , Dijit 中存放的是 Dojo 所有的 Widget 组件,而 DojoX 则是一些扩展或试验功能,DojoX 中的试验功能在成熟之后有可能在后续版本中移入到 Dojo 或 Dijit 命名空间中。 由于 Dojo 包种类...
  • Dojo区别于其他JavaScript库的一点就是它的作用范围。你可以简单的使用Dojo基础功能、DOM、Ajax、特效和其他常见功能,但其实...在这篇教程中,我们将快速浏览Dojo Toolkit,介绍每个发行版本的一些其他装配组件
  • Dojo 技术专题

    2009-12-31 16:44:00
    IBM技术站点整理的一篇不错的学习DOJO技术的专题: Dojo 入门Dojo 与 Web 2.0Dojo 使用技巧掌握 Dojo 工具包系列本地化和国际化可访问性开发Dojo 测试
  • 存档日期:2019年5月14日 | 首次发布:2011年8月23日 了解Dojo Mobile 1.7,它是移动Web开发框架的最新版本,它是Dojo工具包的扩展。 了解如何从主干下载Dojo 1.7,以及如何在应用程序中使用Dojo Mobile。 探索它...
  • dojo validate

    2009-01-07 12:44:23
    所有的控件(除了日期框)都用ValidationTextBox,然后在其的属性中添加正则表达式校验就可以了。 比如: 然后在script中定义这样一个函数: function IsNumber(){ return "^\\d+$";} 2. dijit....
  • 尽管许多开发人员可能认为Dojo仅提供用于PC浏览器的小部件,但实际上出现了令人兴奋的组件,使开发人员能够轻松地将目标对准移动平台。 该内容是《 IBM WebSphere开发者技术期刊》的一部分 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,174
精华内容 469
关键字:

dojo日期组件