难度:中级 Dojo版本:1.8
参考:深入理解_WidgetBase
http://blog.csdn.net/dojotoolkit/article/details/7860938
开始
Dijit的基础以及创建自定义部件的能力,很大程度上依赖于一个定义在
dijit/_WidgetBase模块的基类,这是使用Dojo创建任何种类的自定义部件时都要用到的。
注意早期的dijit/_Widget模块继承了dijit/_WidgetBase,但是在自定义部件时推荐直接继承dijit/_WidgetBase。
理解部件的生命周期是理解Dijit系统最重要的一点,主要是指从部件的创建,到完全可为应用所用,再到销毁部件和相关的DOM节点。
Widget和WidgetBase前面有下划线_,是因为它们不直接使用,而是通过Dojo的declare机制来继承。
dijit/_WidgetBase定义了两条主线:一组在创建过程中顺序调用的方法,以及一种在应用中使用部件时以最小的数据绑定来获取/设置属性的方法。
Dijit生命周期
任何声明以
_WidgetBase为基类的部件在其实例化过程中都会依次调用几个特定的方法。下面以调用顺序列出这些方法:
-
constructor
(所有原型通用,实例化时调用) -
postscript
(使用declare声明时所有原型通用)-
create
-
postMixInProperties
-
buildRendering
-
postCreate
-
-
-
startup
这些方法用于处理以下事情:
- 何时定义初始值
- 如何创建这些值的可视化表示
- 这些可视化表示放到DOM中位置
- 何时处理放到文档中部件DOM节点的逻辑依赖(如DOM节点的大小)
postCreate()
创建自定义部件首先最重要的方法是
postCreate。当部件的所有性质已定义,代表该部件的文档结构已建立,但是还没有加入到主文档时,这个方法被调用。这个方法是部件呈现给用户之前,有机会做最后的调整的主要场所,包括设置任何种类的自定义属性等等。在开发一个自定义部件时,大多数(如果不是所有的话)定制发生在这里。
startup()
Dijit生命周期中第二重要的方法就是
startup,用于在任何DOM结构实际加入到主文档后被调用。在这个方法之前,任何潜在的子部件都已被创建和启动,这对于如部件布局的复合部件很有用。
注意当以编程式方式实例化一个部件,将其放到文档中之后必须调用部件的startup()方法。创建部件后忘记调用startup是一种常见的错误,这会导致部件显示不正常。
销毁方法
dijit/_WidgetBase也定义了一些销毁方法(以调用顺序列出):
-
destroyRecursive
-
destroyDescendants
-
destroy
-
uninitialize
-
destroyRendering
-
-
在自定义部件时,任何必要的自定义销毁行为都应当定义在
destroy方法,记得要调用
this.inherited(arguments)。Dijit可以自动处理节点和大多数对象,使用前面的销毁方法。
注意虽然destroy是任何部件的核心销毁方法,但在显式销毁一个部件时建议调用destroyRecursive,保证部件自己和任何子部件被销毁。
节点引用
一个部件一般是某种用户界面,具有某种DOM结构。
_WidgetBase定义了一个标准性质
domNode,为包括整个部件的父节点的DOM节点的引用,如要做些什么(如在文档中移动整个部件)随时可以获取该节点的引用,且在
postCreate方法被调用时已存在。
除了
domNode,一些部件也定义了
containerNode性质,这是对部件中子节点的引用,其中可能包含内容或是在部件定义外定义的其它部件,例如位于原始源节点中的声明式实例化的子部件。
该性质存在于所有继承自dijit/_Container的部件。
Getter和Setter
_WidgetBase也提供了许多所有部件需要的预定义的性质,以及一套使用标准的
get和
set方法定义自定义的
getters和
setters的机制,这些在所有部件中都预定义了。可以在代码中根据以下的模式定义自定义私有方法来实现:
// for the field "foo" in your widget:
// custom getter
_getFooAttr: function(){ /* do something and return a value */ },
// custom setter
_setFooAttr: function(value){ /* do something to set a value */ }
若以这种方式定义了自定义方法对,可以在自定义部件的实例中使用_WidgetBase的标准get和set方法访问属性。例如对于以上的例子可以这么做:
// assume that the widget instance is "myWidget":
// get the value of "foo":
var value = myWidget.get("foo");
// set the value of "foo":
myWidget.set("foo", someValue);
该标准允许其它部件和控制代码以统一的方式和一个部件交互,且当一个字段被访问时给予执行自定义逻辑的能力(如对DOM片段的修改等),或是调用其它方法(如事件处理或通知)。例如,部件有自定义属性
value,想要在其值改变时通知其它人(可能通过定义的
onChange方法):
// assume our field is called "value":
_setValueAttr: function(value){
this.onChange(this.value, value);
this._set("value", value);
},
// a function designed to work with dojo/on
onChange: function(oldValue, newValue){ }
可见在自定义部件中定制
getter和
setter行为很方便。
注意在定义部件时,应当在任何需要定义自定义逻辑来实现自定义性质的获取和修改的时候,创建自定义的getter和setter方法。在使用自定义部件时,应当总是使用get()和set()方法访问字段,以便恰当的使用自定义的getters和setters。另外,定义自定义setter方法时,应当总是使用内部的_set方法来更新内部值,这使得和dojo/Stateful的watch功能正确衔接,这也是所有部件都继承的基类。
获得句柄
_WidgetBase提供了注册为部件所有的句柄的方法,这应当用于任何由部件所创建的句柄,经常在
postCreate()中监听
DOMNode 事件设置。
将句柄附加到部件的方法是
.own(),其用法很简单:
this.own(
on(someDomNode, "click", lang.hitch(this, "myOnClickHandler)"),
apsect.after(someObject, "someFunc", lang.hitch(this, "mySomeFuncHandler)"),
topic.subscribe("/some/topic", function(){ ... }),
...
);
在部件的基础设施中使用
own()的优点在于在内部部件能跟踪其所有的句柄,保证当部件被销毁时每个都断开连接和/或取消订阅,防止任何种类的内存泄漏。
预定义的性质和事件
_WidgetBase提供了一套预定义的性质,以及在适用时合适的
getters和
setters :
-
id
: 标识部件的唯一字符串 -
lang
: 一个很少用的字符串,可以覆盖默认的Dojo locale -
dir
: 用于双向支持 -
class
: 部件的domNode的HTMLclass属性
-
style
: 部件的domNode的HTMLstyle属性
-
title
: 通常是原生的工具提示的HTMLtitle属性
-
baseClass
: 部件的根CSS class -
srcNodeRef
: 在被“控件化”之前存在的原始DOM节点,若是有的话。注意取决于部件的类型(如模板部件),可能在postCreate后被重置,因为原始节点被丢弃了