麻雀虽小五脏俱全 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 相关文章推荐
JavaScript 节点操作 以及DOMDocument属性和方法
Dec 06 Javascript
jquery插件 cluetip 关键词注释
Jan 12 Javascript
JavaScript改变HTML元素的样式改变CSS及元素属性
Nov 12 Javascript
jquery图片播放浏览插件prettyPhoto使用详解
Dec 19 Javascript
jQuery实现checkbox全选的方法
Jun 10 Javascript
jquery带动画效果幻灯片特效代码
Aug 27 Javascript
vue实现nav导航栏的方法
Dec 13 Javascript
Vue组件实现触底判断
Jun 26 Javascript
jQuery-Citys省市区三级菜单联动插件使用详解
Jul 26 jQuery
vue自动化路由的实现代码
Sep 30 Javascript
AngularJS动态生成select下拉框的方法实例
Nov 17 Javascript
js判断一个对象是数组(函数)的方法实例
Dec 19 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排序算法之直接插入排序(Straight Insertion Sort)实例分析
2018/04/20 PHP
JavaScript去掉空格的方法集合
2010/12/28 Javascript
nodejs npm install全局安装和本地安装的区别
2014/06/05 NodeJs
js实现文字跟随鼠标移动而移动的方法
2015/02/28 Javascript
JavaScript随机生成信用卡卡号的方法
2015/04/07 Javascript
JavaScript简单遍历DOM对象所有属性的实现方法
2015/10/21 Javascript
js日期插件dateHelp获取本月、三个月、今年的日期
2016/03/07 Javascript
Bootstrap框架动态生成Web页面文章内目录的方法
2016/05/12 Javascript
js获取form表单所有数据的简单方法
2016/08/18 Javascript
Bootstrap简单表单显示学习笔记
2016/11/15 Javascript
100多个基础常用JS函数和语法集合大全
2017/02/16 Javascript
AngularJS折叠菜单实现方法示例
2017/05/18 Javascript
JS基于开关思想实现的数组去重功能【案例】
2019/02/18 Javascript
webpack-mvc 传统多页面组件化开发详解
2019/05/07 Javascript
使用vue自定义指令开发表单验证插件validate.js
2019/05/23 Javascript
小程序和web画三角形实现解析
2019/09/02 Javascript
JS动态图片的实现方法完整示例
2020/01/13 Javascript
js实现幻灯片轮播图
2020/08/14 Javascript
js实现类选择器和name属性选择器的示例步骤
2021/02/07 Javascript
[03:37]2014DOTA2国际邀请赛 主赛事第一日胜者组TOPPLAY
2014/07/19 DOTA
快速实现基于Python的微信聊天机器人示例代码
2017/03/03 Python
python使用threading.Condition交替打印两个字符
2019/05/07 Python
python matplotlib.pyplot.plot()参数用法
2020/04/14 Python
利用python制作拼图小游戏的全过程
2020/12/04 Python
python调用百度AI接口实现人流量统计
2021/02/03 Python
html5指南-1.html5全局属性(html5 global attributes)深入理解
2013/01/07 HTML / CSS
法国时尚品牌乐都特瑞士站:La Redoute瑞士
2016/09/05 全球购物
关于人生的感言
2014/01/17 职场文书
小学假期安全广播稿
2014/09/28 职场文书
医院领导班子查摆问题对照检查材料思想汇报
2014/10/08 职场文书
夫妻房产协议书的格式
2014/10/11 职场文书
部队2014年终工作总结
2014/11/27 职场文书
大学生考试作弊被抓检讨书
2014/12/27 职场文书
《葡萄沟》教学反思
2016/02/23 职场文书
爱岗敬业事迹材料
2019/06/20 职场文书
详解Vue中$props、$attrs和$listeners的使用方法
2022/02/18 Vue.js