麻雀虽小五脏俱全 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 相关文章推荐
TopList标签和JavaScript结合两例
Aug 12 Javascript
javascript实现的HashMap类代码
Jun 27 Javascript
点击标签切换和自动切换DIV选项卡
Aug 10 Javascript
jQuery基础知识小结
Dec 22 Javascript
EasyUi combotree 实现动态加载树节点
Apr 01 Javascript
Bootstrap布局组件教程之Bootstrap下拉菜单
Jun 12 Javascript
jQuery实现动态添加和删除input框实例代码
Mar 26 jQuery
vue项目部署到nginx/tomcat服务器的实现
Aug 26 Javascript
uni-app 组件里面获取元素宽高的实现
Dec 27 Javascript
Vue + Scss 动态切换主题颜色实现换肤的示例代码
Apr 27 Javascript
OpenLayer学习之自定义测量控件
Sep 28 Javascript
JavaScript Html实现移动端红包雨功能页面
Jan 10 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
强烈声明: 不要使用(include/require)_once
2013/06/06 PHP
PHP使用mysql_fetch_object从查询结果中获取对象集的方法
2015/03/18 PHP
PHP实现通过Luhn算法校验信用卡卡号是否有效
2015/03/23 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
PHP+Ajax实现的检测用户名功能简单示例
2019/02/12 PHP
优化innerHTML操作(提高代码执行效率)
2011/08/20 Javascript
javascript模拟select,jselect的方法实现
2012/11/08 Javascript
js日期时间补零的小例子
2013/03/05 Javascript
js的image onload事件使用遇到的问题
2014/07/15 Javascript
用javascript关闭本窗口不弹出询问框的方法
2014/09/12 Javascript
js实现选中页面文字将其分享到新浪微博
2015/11/05 Javascript
jquery横向纵向鼠标滚轮全屏切换
2017/02/27 Javascript
详解JS中的attribute属性
2017/04/25 Javascript
前端构建工具之gulp的语法教程
2017/06/12 Javascript
详解React Native开源时间日期选择器组件(react-native-datetime)
2017/09/13 Javascript
javascript将json格式数组下载为excel表格的方法
2017/12/22 Javascript
详解基于Vue2.0实现的移动端弹窗(Alert, Confirm, Toast)组件
2018/08/02 Javascript
实例详解vue.js浅度监听和深度监听及watch用法
2018/08/16 Javascript
ES6知识点整理之函数数组参数的默认值及其解构应用示例
2019/04/17 Javascript
vue使用swiper.js重叠轮播组建样式
2019/11/14 Javascript
python中sleep函数用法实例分析
2015/04/29 Python
Python实现替换文件中指定内容的方法
2018/03/19 Python
Python+threading模块对单个接口进行并发测试
2019/06/25 Python
django-allauth入门学习和使用详解
2019/07/03 Python
Python爬取智联招聘数据分析师岗位相关信息的方法
2019/08/13 Python
pytorch 实现打印模型的参数值
2019/12/30 Python
python-图片流传输的思路及示例(url转换二维码)
2020/12/21 Python
MANGO官方网站:西班牙芒果服装品牌
2017/01/15 全球购物
综合办公室主任岗位职责
2014/04/13 职场文书
群众路线领导对照材料
2014/08/23 职场文书
2014年实习班主任工作总结
2014/11/08 职场文书
招标保密承诺书
2015/01/20 职场文书
遗失说明具结保证书
2015/02/26 职场文书
2016年小学“我们的节日·中秋节”活动总结
2016/04/05 职场文书
分析mysql中一条SQL查询语句是如何执行的
2021/06/21 MySQL
nginx.conf配置文件结构小结
2022/04/08 Servers