我为人人,人人为我

PLM,PDM制造业的制胜法宝
posts - 16, comments - 9, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Dojo之Widget标签开发

Posted on 2007-07-29 13:40 Glen 阅读(3532) 评论(1)  编辑  收藏 所属分类: Ajax学习

DojoWidget标签开发

     Dojo widget就像是jsp中的自定义标签,通过学习开发widget标签来对其使用及其设计原理有更好的了解。本文主要是对Develop HTML widgets with Dojo一文的学习和翻译。由于本人水平有限,如有不妥或者不对之处轻各位大虾批评指正 

1.    Dojo widget的概念

正如上所述,dojo widget就像是jsp中自定义标签,只是dojo widget是在客户端使用的(本文中统一简称dojo widgetwidget标签)。Widget标签已经脱离了传统的DOM模型结构,每个Widget标签都有唯一的widgetID,并且可以包含多个属性,而且可以包含子Widget标签。Widget共包含三个部分:

l         一个包含Widget标签逻辑的js文件,通过JavaScript DOM模型来处理可见的元素。

l         HTML模板文件,它提供基本的Widget HTML视图。当然如果模板很简单,完全可以在js文件中用字符类型替代。

l         Css样式文件,定义标签的样式,在js代码或者HTML模板文件中使用。

l         图片文件。

目录结构如下:

    dojo/src/widget ------------------------------------ js代码文件

     dojo/src/widget/templates ------------------------ HTML模板,Css样式文件

     dojo/src/widget/templates/images --------------- 图片文件

 

2.    Widget标签的使用

使用标准的Dojo Widget标签创建Button按钮,代码如下: 

<html>

<head>

    <script type="text/javascript" src="js/dojo/dojo.js"></script>

    <script type="text/javascript">

       dojo.require("dojo.widget.Button");

    </script>

</head>

<body>

    <div dojoType="Button">Submit</div>

    <!--另一种使用Widget标签的方法-->

    <!--<dojo:button caption="Submit"></dojo:button>-->

</body>

</html>

 

    执行效果如图:

   

 3.    自定义Widget标签-HelloWorld

首先创建js/dojo/src/Widget/templates/HelloWorldTemplate.html,代码如下:

 

<div>

    HelloWorld

</div>

 

创建js/dojo/src/Widget/HelloWorl.js,代码如下:

 

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld",

dojo.widget.HtmlWidget,

    {    templatePath:dojo.uri.dojoUri("src/widget/templates/HelloWorldTemplate.html")

    }

);

 

注:所有用户自定义Widget标签都必须继承HtmlWidget 

创建测试文件HelloWorld.html,代码如下:

 

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.*");

    dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<title>Hello World Widget test</title>

<body>

 

    <div dojoType="HelloWorld"></div>

    <dojo:HelloWorld></dojo:button>

</body>

</html>

 

如果HelloWorldTemplate模板足够简单,可以使用templateString替换templatePath,修改后HelloWorld.js代码如下:

 

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div>Hello World</div>"

    }

);

 

4.    自定义Widget标签属性

以上部分讨论了如何创建简单的自定义标签,下面需要给HelloWorld添加属性以及自样式,让其更像一个标准的Html标签。让HelloWorld标签的显示内容可以有用户定义,添加text属性就可以办到。修改后的代码如下: 

HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div>${this.text}</div>",

       text: ""//default value    

    }

);

 

注:自定义属性必须要设置默认值,否则会被Dojo忽略。而且Dojo会忽略DOM模型下的所有属性。 

HelloWorld.html

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.*");

    dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<title>Hello World Widget test</title>

<body>

 

    <div dojoType="HelloWorld" text="you can set the text attribute"></div>

    <!--<dojo:HelloWorld text="you can set the text attribute"></dojo:button>-->

</body>

</html>

 

属性的处理

    处理属性的典型方法是postCreate()方法(稍候讨论),另一个方法是fillInTemplate()。许多Widget标签都是通过postCreate()方法来处理属性的,也有通过set方法。不同的是postCreate()方法是在标签创建时处理属性,而set方法是在运行时动态设置属性。 

脚本片断

    HEML模板文件中加入js代码并不是一个好的方法,但有时候却必不可少。在Dojo中可以使用${…}代码片断来获取属性值,正如上例中的${this.text} 

添加样式

    为了使Widget达到真正的功用,Dojo提供了定制css样式的功能,通过引用不同的自定义样式,可以方便的为应用改变显示效果。为HelloWorld标签添加样式,创建一个简单样式文件js/dojo/src/widget/templates/HtmlHelloWorld.css,代码如下: 

.caption {

    font-family: Verdana;

    font-size: 10pt;

}

 

注:css类名必须是唯一的

修改HeolloWorld.js,代码如下: 

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div class=\"caption\">${this.text}</div>",

       text: "",//default value

       templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.css")

    }

);

 

5.    js中使用Widget标签

本部分将说明如何用Dojojs代码中使用HelloWorld标签,而传统的js方式已经不再适用。 

传统方式操作Widget标签

    如果想在程序中动态改变text Hello World”,你会试着用传统的js方式来实现,但是这样做是徒劳的。传统方式的代码如下: 

<html>

<head>

<script type="text/javascript" src=" js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body onload="document.getElementById('HelloWorldTest').innerHTML='New

text';">

    <div id=" HelloWorldTest" dojoType="HelloWorld"></div>

</body>

</html>

 

这样的代码是没有任何效果的。下面就分析一下这段为何不会有作用。

A.      Body中的onload属性失效

Body中的onload属性与Dojo是不兼容的,Dojo已经在事件方法中包括了onload的事件。Onload事件在Dojo下使用,代码如下:

<html>

<head>

...

<script>

    dojo.addOnLoad(

       function(){

           alert("onload!");

       }

    );

</script>

</head>

 

B.      Dojo Widget标签与DOM element的区别

Dojo Widget标签已经不再是一个DOM elementDojo创建Widget标签时,已经去掉所有DOM模式下的所有属性,除了Dojo认识的属性。例如,id已经演化成了widgetId。如果需要用传统的方式操作属性,必须通过修改模板文件来实现。如果需要获取ID,修改模板文件代码如下: 

<div id="${this.widgetId}">Hello World</div>

Dojo方式操作Widget标签

    如果要用Dojo方式操作Widget标签,必须还要修改一些代码。修改后的HelloWorld.js代码如下:

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div dojoAttachPoint=\"domNode\" >${this.text}</div>",

       text: "",//default value

       // dynamic setters

       setHtml: function(htmlString) {

           this.domNode.innerHTML = htmlString;

       }     

    }

);

 

注:Dojo Widget标签使用attachment points来处理DOM element。在Dojo方式下,不需要id=”${this.widgetId}”,因为不会使用id来获取对象,而是使用attachment point。实际上attachment point是默认使用的。”domNode”attachment points根元素 

通过获取Widget标签对象实例,代码如下:   

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript"> dojo.require("dojo.widget.HelloWorld");

    dojo.addOnLoad(function(){

       dojo.widget.byId("someID").setHtml("New text");

    });

</script>

</head>

<body>

    <div id="someID" dojoType="HelloWorld"></div>

</body>

</html>

 

通过使用dojo.widget.createWidget()方法动态创建HelloWorld实例,代码如下:

 

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.HelloWorld");

    dojo.addOnLoad(

       function(){

           var newWidget = dojo.widget.createWidget(

           "HelloWorld", // widgetType

           {}, // widget attributes, for example {title: "Some Title"}

           dojo.byId("widgetPlaceholder") // reference to a DOM node that

           // will be REPLACED by new widget

           );

       }

    );

</script>

</head>

<body>

    <div id="widgetPlaceholder"></div>

</body>

</html>

 

6.    Widget标签嵌套HTML

本部分讨论如何实现Widget标签的嵌套 

A.      嵌套静态HTML

正如前面提到的Dojo创建Widget标签时移除所有的DOM element。所以在Dojo移除之前,必须改变所要的DOM element。通过Dojo提供fillInTemplate()方法实现。此方法可以操作HTML DOM element和已经生成的Widget标签。实现改变静态HTMLHelloWorld.js代码如下:

 

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div dojoAttachPoint=\"domNode\">${this.text}</div>",

       text: "",//default value

       // dynamic setters

       setHtml: function(htmlString) {

           this.domNode.innerHTML = htmlString;

       },

      

       fillInTemplate: function(args, frag) {

           // Getting original HTML element

           var source = this.getFragNodeRef(frag);

           // Moving all children of original element to

           // the desired node of the new component

           while(source.hasChildNodes()) {

              var node = dojo.dom.removeNode(source.firstChild);

              this.domNode.appendChild(node);   

           }

           // Invoking original dojo fillInTemplate() method

        dojo.widget.HelloWorld.superclass.fillInTemplate.call(this, args, frag);

       }

    }

);

 

以上代码将HTML DOM节点转移到需要的地方,另一种实现方法是设置Widet属性isContaintertrue 

动态添加嵌套HTML

    如何动态添加嵌套HTML实现方法要根据动态HTML的形式来决定:

l         嵌套HTML作为string提供,通过设置innerHtml属性实现。

l         嵌套HTML作为DOM节点提供,可以使用appendChild方法实现。

以上方式的实现代码如下:

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div>${this.text}</div>",

       text: "",//default value

       setHtml: function(html) {

           if (dojo.lang.isString(html)) {

              this.domNode.innerHTML = html;

           } else if (dojo.dom.isNode(html)) {

              // Cleaning whatever was there before

              dojo.dom.removeChildren(this.domNode);

              // Adding new element

              this.domNode.appendChild(html);

           } else {

              dojo.lang.assert(false, "setHtml called with incorrect type: " + (typeof html));

           }

       }     

    }

);

 

 

7.    Widget标签嵌套Widget标签 

嵌套静态Widget标签

    有些情况下我们需要实现Widget标签的相互嵌套,例如Dojo TabContainerTree标签。要实现这样的Widget标签,你需要设置isContainertrue,而且要在模板中设置attachment point”containerNode”,代码如下:

 

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div dojoAttachPoint=\"containerNode\">${this.text}</div>",

       text: "",//default value

       isContainer: true

    }

);

 

这种实现是依赖Dojo的,如果需要实现更加复杂的,必须要操作postCreate方法中的Children数组,数组中存了所有嵌套的静态Widget标签。

测试代码:

 

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.Button");

    dojo.require("dojo.widget.HelloWorld");  

</script>

</head>

<title>Hello World Widget test</title>

<body>

    <div dojoType="HelloWorld" text="   ad you can set the text attribute">

       <div dojoType="Button">Submit</div>

    </div>

    <!--<dojo:HelloWorld text="you can set the text attribute"></dojo:button>-->

</body>

</html>

 

复杂应用请参考Dojo TabContainerTree标签。 

动态添加Widget标签嵌套

    动态添加Widget标签嵌套,需要在HelloWorld.js中实现addChild()方法,重写addChild()方法中还要调用父类的addChild()方法。实现动静态添加Widget标签嵌套的代码如下:

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: "<div dojoAttachPoint=\"titleNode\">${this.text}" +

                       "<br/><div dojoAttachPoint=\"containerNode\">"

                     + "</div></div>",

       text: "",//default value

       isContainer: true,

       postCreate: function() {

           // adding statically

           for(var i in this.children) {

              this._addRow(this.children[i]);

           }

       },

       addChild: function(child, overrideContainerNode,

           pos, ref, insertIndex) {

           this._addRow(child);

           dojo.widget.HelloWorld.superclass.addChild.call(

           this, child, overrideContainerNode);

       },

       _addRow: function(component) {

           this.titleNode.appendChild(

           document.createTextNode(component.widgetType));

           this.titleNode.appendChild(

           document.createElement("br"));

       }

    }

);

 

注:经测试发现,即使不实现addChild方法,同样可以动态添加Widget标签嵌套,但是在HtmlWidget类中也没有找到addChild方法的实现,这里有待进一步研究。 

测试代码:

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.Button");

    dojo.require("dojo.widget.Checkbox");

    dojo.require("dojo.widget.HelloWorld");

      

    dojo.addOnLoad(function(){

       var button = dojo.widget.createWidget("Button",

                         {caption: "Submit"});

       dojo.widget.byId('someID').addChild(button);

       var checkbox = dojo.widget.createWidget("Checkbox");

       dojo.widget.byId('someID').addChild(checkbox);

    });

</script>

</head>

<title>Hello World Widget test</title>

<body>

    <div dojoType="HelloWorld" id="someID"></div>

    <!--<dojo:HelloWorld text="you can set the text attribute"></dojo:button>-->

</body>

</html>

 

8.    Dojo事件处理

本部分主要介绍使用Dojo的方式处理事件,在阅读本部分之前,最好先了解Dojo事件系统。首先需要在模板中定义dojoAttachEvent=”eventName: eventHandlerMethod;”属性。eventName是标准的DOM事件名称(例如:onClick)eventHandlerMethod则为事件调用函数。修改后的代码如下:

 

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget,

    {

       templateString: '<div dojoAttachPoint="domNode" dojoAttachEvent="onClick:onClickHandler;">Click here</div>',      

       onClickHandler: function(e) {

           alert("clicked in onClickHandler");

           this.onClick(e);                  

       },

       onClick:function (e) { //for dojo.event.connect

       }

    }

);

 

注:可以在标签中预定义某一事件的函数,如上例中的onClickHandler,同时也可以预留接口让用户绑定自定义函数。 

测试代码:

 

<html>

<head>

<script type="text/javascript" src="js/dojo/dojo.js"></script>

<script type="text/javascript">

    dojo.require("dojo.widget.HelloWorld");

    function HelloWorld_onClick() {

       alert("Node clicked in HelloWorld_onClick");

    }  

    dojo.addOnLoad(function(){

       var hello = dojo.widget.byId("someID");

       dojo.event.connect(hello, 'onClick', 'HelloWorld_onClick')

    });

</script>

</head>

<title>Hello World Widget test</title>

<body>

    <div dojoType="HelloWorld" id="someID"></div>

</body>

</html>

 

总结:

通过对本文的学习,初步了解了DojoWidget标签的简单使用和如何实现自定义Widget标签。

 



做人简单一点好


评论

# re: Dojo之Widget标签开发  回复  更多评论   

2007-12-28 12:30 by vincent,headhunter
i am a headhunter and now i am searching an IT Operation Mgr who should has experience in retail industry or supermarket , basic requirement is fluent written and spoken English ,this position is for a corp of fortune 500 and will base in HQ, another position is senior programmer who should familar with java,oracle and has experience in insurance in insurance company.if you are interested pls contact 13701017004,or
freeshi2007@hotmail.com
thanks
yours sincerely Vincent

只有注册用户登录后才能发表评论。


网站导航: