学习Ajax框架之dojo:第十三节——如何编写自己的dojo widget

 

Dojo开发包本身提供了多种widget,它们涵盖了大部分在web开发中可能会使用的界面组件,如下拉菜单、树形菜单等,开发人员只需要在JavaScript代码中声明对特定widget的引用,就可以使用标记的方式在页面中加入widget。当然这些widget并不一定能完成满足实际应用的需要,开发人员也可以通过继承的方式在现有widget的基础上进行功能扩展。

此外,在web应用中可能会有多处地方使用相同或者类似的界面,因此在页面中可能会有大量类似或者重复的代码。这时开发人员可以定义新的widget,在页面中使用标记的方式实现界面代码的重用。

1. 扩展Dojo自带widget

第一种自定义widget的方法是扩展Dojo开发包自带的widget,下面以按钮widget为例进行widget的扩展。我们的目标是修改按钮的显示风格,包括各种状态下按钮的背景图片。

(1)   定义widget子类

首先,在test\mywidget目录下新建一个JavaScript代码文件Button.js,其中定义了一个继承自dojo.widget.Buttonwidget,使用的函数是dojo.widget.defineWidget,具体代码如下:

//扩展widget的包名

Dojo.provide(“my.widget.Button”);

Dojo.require(“dojo.widget.Button”);

//定义一个新的widget

Dojo.widget.defineWidget(

           //类名

           “my.widget.Button”,

           //父类

           Dojo.widget.Button,

           //覆盖父类的若干属性

           {

                    //更换按钮的背景图片

                    InactiveImg: “test/mywidget/inactive”,

                    activeImg: “test/mywidget/active-”,

                    pressedImg: “test/mywidget/pressed-”,

                    diaabledImg: “test/mywidget/diaabled-”,

}

);

 

上面的代码通过覆盖父类的相关属性更换了4种状态(inactiveactivepresseddisabled)下按钮的背景图片。

(2)   注册模块路径

Button.js的代码指明扩展的widget对应的类是my.widget.Button,因此使用这个widget必须引入my.widget.Button类。仅仅通过dojo.require语句是不够的,Dojo并不知道Button.js代码所在的路径,因此首先要调用dojo.registerModulePath方法注册模块路径。模块路径的概念相当于java中的类路径,Dojo会在模块路径下寻找相关类的执行代码,模块路径的起始位置是dojo.js所在的目录。注册模块路径的代码如下所示:

Dojo.registerModulePath(“my.widget”, “test/mywidget”);

Dojo.require(“my.widget.Button”);

 

(3)   使用widget

现在可以用标记的方式在页面中调用自定义的按钮widget,例如:

<button dojoType=”my:Button”>

<div class=”text” style=”width:50px;height:20px”>button</div>

</button>

 

这里使用my作为Button的前缀,与Dojo自带的Button widget所示区别。

 

 

2. 定义新的widget

某些情况下,在Dojo自带的widget的基础上进行扩展不能满足应用的需要,这时就需要从头开始打造一个全新的widget。一个widget的定义通常包括以下内容:

1)         显示模板(HTML页面和CSS样式);

2)         内容和属性的定义;

3)         事件的定义。

下面介绍开发自定义widget的一般步骤。以实现简单的便签页面组件为例。如图1所示。

学习Ajax框架之dojo:第十三节——如何编写自己的dojo widget_第1张图片

            图1 自定义widget效果图

在页面中可以通过如下的代码调用该widget

<div dojoType=”my:Memo” title=”测试标题”>

文本内容……

</div>

 

1)定义widget的显示模板

自定义widget的第1步是准备widget的显示模板,它一般由两部分组成:HTML页面和CSS样式表。相关代码比较简单,如下所示:

Memo.html:

<div class=”memo”>

<div class=”title”>Memo Title</div>

<div class=”close”>X</div>

<div class=”contents”> </div>

</div>

Memo.css()

 

2)声明widget

2步是在JavaScript代码中给出widget的定义,对于在HTML页面中使用的widget来说,它们的基类是dojo.widget.HtmlWidget。自定义的widget类必须覆盖基类dojo.widget.HtmlWidget的两个属性:templatePathtemplateCssPath,它们分别是HTML模板和CSS模板文件的路径。具体实现代码(Memo.js)如下所示:

//给出自定义widget的类名

Dojo.provide(“my.widget.Memo”);

Dojo.require(“dojo.widget.HtmlWidget”);

Dojo.widget.defineWidget(

           //widget对应的类

           “my.widget.Memo”,

           //widget的基类是Dojo.widget. HtmlWidget

           Dojo.widget. HtmlWidget,

           //覆盖基类的属性

           {

                    //模板HTML的路径

                    templatePath: dojo.uri.dojoUri(“test/mywidget/Memo.html”),

                    //模板CSS的路径

                    templateCssPath: dojo.uri.dojoUri(“test/mywidget/Memo.css”)

}

);

 

3)处理widget的内容和参数

运行上面的代码,可以得知widget还存在两个问题:

1)         Widget内部的内容完全被忽略,没有显示在页面上;

2)         便签的标题不能以属性的方式进行声明,始终显示固定的文字“Memo Title”。

Dojo widget中只有容器类型的widget才能处理其内部的HTML代码。设置容器类型widget的方法是:覆盖基类Dojo.widget. HtmlWidget的属性isContainer,将其设置为true。对Memo.js进行修改,代码如下所示:

……

//覆盖基类的属性

           {

                    //widget是一个容器

                    isContainertrue,

//模板HTML的路径

                    templatePath: dojo.uri.dojoUri(“test/mywidget/Memo.html”),

                    //模板CSS的路径

                    templateCssPath: dojo.uri.dojoUri(“test/mywidget/Memo.css”)

}

         ……

 

容器类型的widget会对其内部的HTML代码进行处理,具体如何显示以及显示在widget的哪一部分,则需要在HTML模板中进行配置。例如在便签widget中,如果希望它内部的HTML代码在widget内部的某个<div>元素中呈现,那么可以这样修改HTML模板的定义:

<div class=”memo”>

<div class=”title”>Memo Title</div>

<div class=”close”>X</div>

<div class=”contents” dojoAttachPoint=”containerNode”> </div>

</div>

 

为了能够使用属性的方式声明便签的标题,需要在widget的定义中增加一个title属,性,同时将其添加到HTML模板中合适的位置。修改后的Memo.jsMemo.html代码如下所示:

Memo.js:

……

//覆盖基类的属性

           {

                    //便签widget的标题

                    title”Memo Title”,

                    //widget是一个容器

                    isContainertrue,

//模板HTML的路径

                    templatePath: dojo.uri.dojoUri(“test/mywidget/Memo.html”),

                    //模板CSS的路径

                    templateCssPath: dojo.uri.dojoUri(“test/mywidget/Memo.css”)

}

         ……

Memo.html:

<div class=”memo”>

<div class=”title”>${this.title}</div>

<div class=”close”>X</div>

<div class=”contents” dojoAttachPoint=”containerNode”> </div>

</div>

其中${this.title}表示widget对象的title属性。

 

4)定义widget的事件

Widget可以看作页面中相对独立的界面组件,它必须具有独立的事件响应机制,才能完成一些复杂的功能。对于便签widget来说,需要增加单击“关闭”按钮的onClick事件。事件的定义是在HTML模板中进行的,下面的代码为“关闭”按钮的<div>元素增加了一个onClick事件。

<div class=”close” dojoAttachEvent=”onClick”>X</div>

 

事件的处理函数可以使用dojo.event.connect方法添加,例如:

Dojo.addOnLoad(function(){

         //widget对象

         Var memo=dojo.widget.byId(“memo”);

//添加widget对象的onClick事件处理函数

Dojo.event.connect(memo, “onClick”, function(evt){

                  Memo.destroy();

});

})

 

Dojo widget的事件名称有“内外”之分,内部事件通常采用DOM事件的名称,例如onclickonmouseover等;而外部事件名称则在为widget添加事件处理函数时使用,缺省情况下外部事件的名称与内部事件相同,如果需要指定外部事件的名称,则需要在相应的dojoAttachEvent属性中使用“内部事件名称:外部事件名称”的形式。例如将便签widgetHTML模板修改为如下的代码:

……

<div class=”close” dojoAttachEvent=”ondblclick:onclick”>X</div>

……

 

此时当“关闭”按钮<div>元素被双击时(即触发内部事件ondblclick),widget的外部事件——onClick事件被触发,页面执行相应的处理函数。

你可能感兴趣的:(学习Ajax框架之dojo:第十三节——如何编写自己的dojo widget)