麻雀虽小五脏俱全 Dojo自定义控件应用


Posted in Javascript onSeptember 04, 2010

现在Javascript框架、控件库有很多,jQuery、Ext、prototype、MooTools、Dojo等等,这些都是在Google上搜索“javascript+framework”列在第一页的。其中,除了MooTools,其它的都有所了解,但只在项目中用过Ext和Dojo。但一直不太喜欢Ext,性能有问题,新的版本还收费了。

另外,Ext官方提供的例子都是用JavaScript来创建和初始化控件,一个JavaScript配套一个HTML来用,这样管理起来很混乱。而且官方例子是Best Practice,所以不太接受这种模式。Dojo在本人眼里是一个缺点和优点都很突出的家伙:

缺点:

1、文档非常之差;

2、CodeBase非常之大(优点乎,缺点乎?);

3、版本演进快,且每次版本演进,都有大量的API发生变化,还不够成熟。

优点:

1、是一个很优秀的控件开发框架;

2、完全体现了javascript面向对象的一面。

EXT和Dojo比起来,本人觉得EXT是一个控件库,而Dojo是一个框架。第一次接触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控件,你需要了解的知识并不太多:

◆一个控件就是一个JS类;

◆所有的控件都继承自_Widget或其子类,_Widget类提供了控件的生命周期管理函数;

◆可以同时继承_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> 
<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中使用,JavaScript代码如下:
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,不好管理。
Javascript 相关文章推荐
DOMAssitant最新版 DOMAssistant 2.5发布
Dec 25 Javascript
基于jQuery的日期选择控件
Oct 27 Javascript
url 特殊字符 传递参数解决方法
Jan 01 Javascript
Jquery公告滚动+AJAX后台得到数据
Apr 14 Javascript
window.returnValue使用方法示例介绍
Jul 03 Javascript
原生js实现模拟滚动条
Jun 15 Javascript
基于JS实现二维码图片固定在右下角某处并跟随滚动条滚动
Feb 08 Javascript
详解Node.js中exports和module.exports的区别
Apr 19 Javascript
微信小程序scroll-view组件实现滚动动画
Jan 31 Javascript
vue学习笔记之Vue中css动画原理简单示例
Feb 29 Javascript
使用Angular9和TypeScript开发RPG游戏的方法
Mar 25 Javascript
mustache.js实现首页元件动态渲染的示例代码
Dec 28 Javascript
JavaScrip单线程引擎工作原理分析
Sep 04 #Javascript
onsubmit阻止form表单提交与onclick的相关操作
Sep 03 #Javascript
判断浏览器的javascript版本的代码
Sep 03 #Javascript
Extjs中DisplayField的日期或者数字格式化扩展
Sep 03 #Javascript
JavaScript的类型简单说明
Sep 03 #Javascript
JavaScript类和继承 this属性使用说明
Sep 03 #Javascript
JavaScript类和继承 prototype属性
Sep 03 #Javascript
You might like
收藏的PHP常用函数 推荐收藏保存
2010/02/21 PHP
PHP面向接口编程 耦合设计模式 简单范例
2011/03/23 PHP
PHP Session 变量的使用方法详解与实例代码
2013/09/11 PHP
Discuz!X中SESSION机制实例详解
2015/09/23 PHP
PHP通过调用新浪API生成t.cn格式短网址链接的方法详解
2019/02/20 PHP
jQuery学习5 jQuery事件模型
2010/02/07 Javascript
json对象转字符串如何实现
2012/12/02 Javascript
简述JavaScript对传统文档对象模型的支持
2015/06/16 Javascript
jquery 重写 ajax提交并判断权限后 使用load方法报错解决方法
2016/01/19 Javascript
Node.js的环境安装配置(使用nvm方式)
2016/10/11 Javascript
JavaScript利用Date实现简单的倒计时实例
2017/01/12 Javascript
Angular中使用MathJax遇到的一些问题
2017/12/15 Javascript
js判断文件类型大小并给出提示的实现方法
2018/01/03 Javascript
Vue组件之单向数据流的解决方法
2018/11/10 Javascript
在微信小程序中使用mqtt服务的方法
2019/12/13 Javascript
vue 输入电话号码自动按3-4-4分割功能的实现代码
2020/04/30 Javascript
微信小程序中的列表切换功能实例代码详解
2020/06/09 Javascript
Python2.5/2.6实用教程 入门基础篇
2009/11/29 Python
python通过索引遍历列表的方法
2015/05/04 Python
常用python编程模板汇总
2016/02/12 Python
Python基于回溯法子集树模板解决数字组合问题实例
2017/09/02 Python
Python面向对象编程基础解析(一)
2017/10/26 Python
解决python读取几千万行的大表内存问题
2018/06/26 Python
python utc datetime转换为时间戳的方法
2019/01/15 Python
python判断一个对象是否可迭代的例子
2019/07/22 Python
python3:excel操作之读取数据并返回字典 + 写入的案例
2020/09/01 Python
Python基于Serializer实现字段验证及序列化
2020/11/04 Python
css3实现wifi信号逐渐增强效果实例
2017/08/09 HTML / CSS
Mountain Hardwear官网:攀岩服装和户外装备
2019/09/26 全球购物
嘻哈珠宝品牌:KRKC&CO
2020/10/19 全球购物
实习教师自我鉴定
2013/12/09 职场文书
文明餐桌活动方案
2014/02/11 职场文书
文明城市创建标语
2014/06/16 职场文书
《世界多美呀》教学反思
2016/02/22 职场文书
[有人@你]你有一封绿色倡议书,请查收!
2019/07/18 职场文书
深入理解python协程
2021/06/15 Python