麻雀虽小,五脏俱全:用DOJO写一个最简单的控件

jinxfei 2009-06-23 06:32:34
加精
现在javascript框架、控件库有很多,JQuery、Ext、prototype、MooTools、DOJO,
这些都是在Google上搜索“javascript+framework”列在第一页的。

这其中,除了MooTools,其它的都有所了解,但只在项目中用过Ext和DOJO。
但一直不太喜欢Ext,性能有问题,新的版本还收费了,
特别讨厌这种打着开源旗号赚钱的,像JGraph,JEP,被忽悠进来套住你就开始收费,

另外,Ext官方提供的例子都是用JS来创建和初始化控件,一个JS配套一个HTML来用,
这样管理起来很混乱。我认为官方例子应该是Best Practice,所以不太接受这种模式。


DOJO在我眼里是一个缺点和优点都很突出的家伙
缺点:
1、文档非常之差
2、CodeBase非常之大(优点乎,缺点乎?)
3、版本演进快,且每次版本演进,都有大量的API发生变化,还不够成熟

优点:
1、是一个很优秀的控件开发框架
2、完全体现了javascript面向对象的一面


EXT和DOJO比起来,我觉得EXT是一个控件库,而DOJO是一个框架
我06年第一次接触DOJO,当时版本0.3.X,今天项目中又有需求想用DOJO,版本是1.3.1,
对比0.3和1.3,发现核心的思路并没有太大变化,但出厂提供的控件却有翻天覆地的变化,
不过已经先入为主的对它的控件有成见,导致现在也没有兴趣再去研究,
还是讲讲如何拿DOJO做自定义的控件吧。

---

DOJO很复杂,但我们可以简单的认为它分三层
1、最底层的是核心API
核心API提供的方法简化了DOM、字符串、CSS、事件等相关的操作。
核心API还实现了类似于Java的package概念和import机制,方便了代码组织和依赖管理。

2、基于核心API,创造了“控件生命周期”概念
这是DOJO的亮点,允许第三方以规范的方式开发控件。
基于DOJO开发的控件具有很强的内聚性和面向对象的特性。

3、基于2所开发的各类控件
DOJO自己提供的控件也比较全了,只是由于历史原因,没有深入研究过。

---

DOJO的控件统称DIJIT,要写出DOJO版的Hello World控件,你需要了解的知识并不太多:
1、一个控件就是一个JS类
2、所有的控件都继承自_Widget或其子类,_Widget类提供了控件的生命周期管理函数
3、可以同时继承_Templated,继承该类,可以为控件绑定模板来描述控件的展示


关于_Widget基类的介绍
1、生命周期方法
_Widget提供了一系列方法称为“生命周期方法”,DOJO框架在初始化一个控件的时候,会依次调用它们,
我们的自定义控件,可以重写特定的方法来加入自己的初始化逻辑,方法调用顺序及说明:
preamble(/*Object*/ params, /*DOMNode*/node)
//这是一个通常不会用到的方法,这个方法的返回值,作为constructor的输入参数param
constructor(/*Object*/ params, /*DOMNode*/node)
// 这个方法相当于java类的构造函数
// 在这个类中执行初始化动作
postscript(/*Object*/ params, /*DOMNode*/node)
//实际的控件创建过程,依次调用如下方法(都可以被重写)
_Widget.create(/*Object*/params, /*DOMNode*/node)
_Widget.postMixInProperties( )
_Widget.buildRendering( )
_Widget.postCreate( )
//我用得最多的是postCreate方法,这个方法中,控件已经初始化完毕,界面上也已经显示出来了,
//通常在这个方法中启动业务相关的处理


2、该类的几个重要属性(控件可以通过this访问)
id: 控件被授予的唯一编号,如果用户不指定,则DOJO随机创建一个
domNode: 该控件在HTML中对应的DOM节点



最基本的自定义控件示例:
js文件:./hello/world.js(以下涉及到文件名,都用相对路径,其中./代表和"dojo,dijit,dojox"同级目录)
//声明自己输出的类名
dojo.provide("hello.world");
//声明自己依赖的类名
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");

//dojo.declare定义控件类,第一个参数:类名,第二个参数:父类数组,第三个参数:类的prototype
dojo.declare("hello.world",[dijit._Widget,dijit._Templated],
{
postCreate:function(){
this.domNode.innerHTML="hellow world";
}
}
);


该控件的行为极其简单,在postCreate方法中,将自己在HTML页面中对应的DOM节点的内容设置为 hellow world

html文件:./helloworld.htm
<html>
<head>
<title>Hello World</title>
<!-- 首先引入dojo.js,modulePaths用来定义包含控件的js目录,类似于jsp的自定义tag引入的机制-->
<script type="text/javascript" src="./dojo/dojo.js" djConfig="parseOnLoad:true,modulePaths:{hello:'../hello'}">
</script>

<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("hello.world"); //引入自定义控件
</script>
</head>
<body>
<div dojoType="hello.world"></div>
</body>
</html>


modulePaths的具体作用和用法,请google即可。



接下来,我们将控件参数化
我们可以在写标签的时候,将名字作为参数传进去,然后控件显示HELLO XXX,
首先将html文件改成:
<html>
<head>
<title>Hello World</title>
<!-- 首先引入dojo.js,modulePaths用来定义包含控件的js目录,类似于jsp的自定义tag引入的机制-->
<script type="text/javascript" src="./dojo/dojo.js" djConfig="parseOnLoad:true,modulePaths:{hello:'../hello'}">
</script>

<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("hello.world");
</script>
</head>
<body>
<div dojoType="hello.world" yourName="jinxfei"></div>
</body>
</html>


大家注意到,我们在标签上增加了“yourName”属性,在控件中如何使用该属性呢?
可以在construtctor方法中接收此属性的值,将值赋给控件类自身的变量,然后在postCreate中使用,
js代码如下:
dojo.provide("hello.world");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");


dojo.declare("hello.world",[dijit._Widget,dijit._Templated],
{
yourName:'world',
constructor:function(params,node){
this.yourName=params.yourName;
},
postCreate:function(){
this.domNode.innerHTML="hellow "+this.yourName;
}
}
);




接下来,我们将进一步增加控件进的复杂性
增加一个输入框,在这个输入框中输入文本的同时,动态更新hello XXX,
这就要用到dojo的事件绑定机制,最常用的模式为:
dojo.connect(node,event,obj,method);
表示将obj的method方法作为domNode的event事件处理函数,
例如:
dojo.connect(inputText,"onkey",this,"updateHello");

这次先改控件,在postCreate的时候,动态增加一个输入框,并为输入框动态绑定事件:
dojo.provide("hello.world");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");


dojo.declare("hello.world",[dijit._Widget,dijit._Templated],
{
yourName:'world',
typeIn:null,
echoDiv:null,
constructor:function(params,node){
this.yourName=params.yourName;
},
postCreate:function(){

this.typeIn=document.createElement("input");

this.typeIn.type="text";
this.domNode.appendChild(this.typeIn);
this.echoDiv=document.createElement("div");
this.domNode.appendChild(this.echoDiv);
dojo.connect(this.typeIn,"onkeyup",this,"updateHello");//动态绑定事件
this.updateHello();//调用方法初始化一下,先显示一个空的hello
} ,
updateHello:function(){
this.echoDiv.innerHTML="hello "+this.typeIn.value;
}
}
);


而HTML文件中对控件的引用,不用做任何改变(严格来讲,你需要删除yourName="jinxfei"这个属性)。

从这个稍微有一点点复杂的控件,我们已经可以看出DOJO的优势
真正的面向对象!
控件管理范畴内的DOM元素,都可以放在类中作为属性来使用(直接用this.xxx引用),
这样,避免了document.getElementByID()满天飞,控件是内聚的。
响应事件的方法也是类的方法,免得在页面中声明大量的离散function,不好管理。


我先歇歇,接下来整理一下DOJO的模板机制,用模板做复杂控件更容易一些,
还有与DWR的结合等等。
...全文
1044 44 打赏 收藏 转发到动态 举报
写回复
用AI写文章
44 条回复
切换为时间正序
请发表友善的回复…
发表回复
FengWorld 2011-04-14
  • 打赏
  • 举报
回复
开源与收费是两码事吧?
aidings 2010-08-07
  • 打赏
  • 举报
回复
"缺点:文档非常之差"
Can't agree more!
reedseutozte 2010-03-10
  • 打赏
  • 举报
回复
LZ
dojo.connect(this.typeIn,"onkeyup",this,"updateHello");//这行代码可能会引起 IE的内存泄漏
修改为
this.connect(this.typeIn,"onkeyup",updateHello);//这个应该可以
_widget基类中定义了connect销毁的时候会把事件处理函数置为null解决内存泄漏
corn107 2010-01-10
  • 打赏
  • 举报
回复
不会 明天看看
timeriver_wang 2009-12-25
  • 打赏
  • 举报
回复
jquery 多好啊
leebin1986 2009-12-19
  • 打赏
  • 举报
回复
用你最初版本的hello/world.js+helloworld.htm跑出来页面报错,错误信息为:_5 is null
[Break on this error] (35 out of range 16) dojo.js (第 35 行)
我用的是dojo-release-1.4.0rc2,请问如何解决?
lovezx1028 2009-06-30
  • 打赏
  • 举报
回复
z xuexi.
jinxfei 2009-06-30
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 healer_kx 的回复:]
dojo的学习曲线是最大的,比MFC还费劲。。。
[/Quote]

实际上还好,跟MFC比,那小巫见大巫了,只是DOJO文档不好,这一点让人头疼。
healer_kx 2009-06-28
  • 打赏
  • 举报
回复
dojo的学习曲线是最大的,比MFC还费劲。。。
robyjeffding 2009-06-27
  • 打赏
  • 举报
回复
JS控件,个人倾向于jquery,DOJO还没用过,学习了!
guaimutou 2009-06-27
  • 打赏
  • 举报
回复
暂时还没精力去学习,但是很感兴趣
emuggle 2009-06-26
  • 打赏
  • 举报
回复
dojo主要的优点体现在他的数据绑定,在js中实现了组件的mvc.
至于所说的jquery的过程式编程优点,dojo提供了dojo.query()方法予以支持.当初设计时不用$也是考虑到命名空间的问题.
Js_xq 2009-06-26
  • 打赏
  • 举报
回复
还是自己写的好点!用一两年框架,连js 是什么都忘了
jinxfei 2009-06-26
  • 打赏
  • 举报
回复
楼上的,不太清楚哦。

我只知道,CSDN的论坛有专门的代码标记,blog好像没有。
janwin 2009-06-26
  • 打赏
  • 举报
回复
问一下楼主,怎么把java代码html,sql代码放入博客中,并格式化,我的意思就是说那些代码高亮在网页中的实现
ranmer 2009-06-26
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 fejay 的回复:]
也鄙视一下收费的EXT。
ext是比较强大,但是有点大,还有就是有很多BUG
[/Quote]

是啊,现在被那些BUG搞死了
dongwei99 2009-06-24
  • 打赏
  • 举报
回复
强烈支持!!!
clarck_913 2009-06-24
  • 打赏
  • 举报
回复
楼主的文章是播种机

收藏了
天涯孤影 2009-06-24
  • 打赏
  • 举报
回复
收藏,慢慢学习!
jinchun1234 2009-06-24
  • 打赏
  • 举报
回复
收藏
加载更多回复(22)
Dojo 客户端调优的方式:   1. 编译合适的dojo文件。   dojo十分“巨大”, 而且有很多文件是最终用户不需要使用的。   默认情况下的dojo.js 比较大,有200多k,但是如果自定义进行编译之后可能只有10多k。   而且将常用的模块编译到dojo.js 也能提高效率。   dojo的加载顺序如下:   1). 浏览器加载dojo.js   dojo bootstrp code   dojo loader   (optionally) frequently used modules   2). dojo.js 激活Dojo对象, 动态的载入其他的module,如果模块已经载入,那么将不会再一次重新载入。   dojo 提供了一系列典型的编译方案可以选择。   dojo 的编译可以减少文件的下载数目,可以使文件大小显著的减少。   2. 减少widget的使用。   每加载一个dojo 的widget都需要额外的时间,所以当然使用越少dojo控件,速度就越快。   3. 使用新版本的dojo,建议1.0以上。   新版本对性能进行了优化,减少了bug,所以尽量选用新的稳定版本。   4. 减少html tag,每增加一个tag,性能的负担就越重,比如   使用
xxxxxxx
  就不如用
xxxxxxx
  5. 优化widget的加载   dojo在页面加载的时候将分析整个HTML文件,自动加载指定的内容为dojo控件。即使你没有定义任何dojo控件。所以优化widget的控件能够显著的提升一个页面加载的性能。

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧