在本教程中,你将会学到Dijit的_WidgetBase模块是什么,与它是如何在Dojo Toolkit中做为所有挂件的根据而存在的。
开始
作为Dijit的基础,让你有能力创建自己的挂件,主要依靠一个基类,它定义在dijit/_WidgetBase模块中。当然搭建一个web应用还要依靠Dojo Toolkit中的其他关键点(如Dojo parser与Dijit templating system),这些模块是使用Dojo Toolkit创建任何种类自定义挂件的关键。
如果你是从早起版本一路走来的,你可以会熟悉dijit/_Widget模块。dijit/_Widget依然存在,它继承自dijit/_WidgetBase。创建自定义的挂件最好继承自dijit/_WidgetBase,因为dijit/_Widget在Dojo 2.0中可以被废弃了。
理解Dijit系统的关键就是挂件的生命周期。生命周期在挂件构建的初期就应该关注,换句话说,从一个挂件的构建到被应用完全使用——通过挂件的析构与他联系的DOM元素。
如果你想知道为什么Widget与WidgetBase前面都有个下划线_,这是因为他们都不是准备直接实例化类使用的模块;相反,他们主要是用来作为基类被继承的。
为了完成这些,dijit/_WidgetBase定义了两个概念:在挂件创建的过程中一系列方法被连续调用,挂件在应用中的生命周期,设置与获取字段的方法使用最新数据绑定。让我们来看第一个原理:Dijit的挂件的生命周期。
Dijit的生命周期
每个挂件都是使用_WidgetBase作为基类被声明,实例化时运行一系列的方法。我们他们的被调用顺序给列了出来:
- constructor
- postscript
- create
- postMixInProperties
- buildReadering
- postCreate
- create
- startup
这些方法主要处理下面这些事情:
-
利用默认的与运行时的值初始化挂件的数据
- 为挂件的视觉表现生成DOM结构
- 放置关键的DOM结构到页面中
- 处理依赖于DOM结构在文档只能中的逻辑表现。
postCreate()
到目前为止,当创建自定义挂件时脑海中最终的方法应该是postCreate。它将在挂件的属性定义与已创建的挂件在文档中呈现后被调用——但在它自己的片段加入到文档之前。这就是它很重要的原因,因为它处在一个很主要的位置,作为一个开发者,这个是在挂件呈现给用户之前做最后修改的机会,包括设置自定义属性等。当开发一个自定义挂件时,自定义部分大多都在这里完成(不是全部)。
startup()
在Dijit的生命周期中第二重要的方法就应该是startup了。这个方法被设计为处理DOM片段真正的添加到文档中之后的事情;它不会被触发直到任何潜在的子挂件被创建和启动。这对于复合挂件与布局挂件非常有用。
当以为编程的方式实例化挂件时,在将其放入文档中时总是要调用的挂件的startu方法。人们经常犯的错就是忘记了调用startup,然后在那抓耳挠腮,苦思不解为什么我们的挂件没有展示出来。
撕下方法(用于析构时调用的方法)
除了实例化方法之外,dijit/_WidgetBase还定义了一些析构方法(按照调用顺序列一下):
- desctroyRecursive
- destroyDescendants
- destroy
- uninitialize
- destroyRendering
当我们编写自定义挂件时,任何用于销毁的动作或行为都应该放在destroy方法中。(不要忘记了调用this.inherited(arguments)!)Dijit自己照顾节点且很多对象为你做好了管理工作(使用上述的这些方法),通常你不用为你从Dijit继承来的方法而担心。
尽管desctroy是任何挂件的中心注销方法,但在你要明确的注销一个挂件时候,调用desctroyRecursive是明智的选择,它不仅可以确保注销挂件自身,还包括他们的子挂件。
节点引用
挂件通常是用户界面的一种,没有某种DOM表现是不完整的。_WidgetBase定义了一个标准属性叫做domNode,它用来引用挂件的父节点。如果你需要利用它做些什么事,可以直接以编程的方式获得这个引用(如在文档中移动挂件),且在postCreate调用的时候它已经可用了。
除了domNode属性之外,一些挂件还有个containerNode属性。这是一个在挂件中子节点的引用或定义在你挂件之外的挂件,就是在一个声明实例化的挂件的源码节点。(译者注:暂时不太理解到时是什么玩意儿)
我们将在另外一个教程中讨论containerNode,这里只需要知道它的存在就好了。(很明显,继承自dijit/_Container的挂件都应该有这个属性)
Getters与Setters
除了启动与销毁等基础方法外,_WidgetBase还为挂件的需要提供了不止一些预定义属性,但是还有一种方式让你自定义getters和setters,那将用标准的get和set方法类工作,在所有的挂件都预定义了。下面是定义私有方法的代码:
1 // for the field "foo" in your widget 2 3 // custom getter 4 _getFooAttr: function() { /* do something and return a value */ }, 5 6 // custom setter 7 _setFooAttr: function(value) { /* do something to set a value */ }
如果你定义了这么一对自定义方法,你就可以使用基于_WidgetBase的挂件实例的标准get与set方法。对于上面的实例,你可以这样:
1 // assume that the widget instance is "myWidget": 2 3 // get the value of "foo" 4 var value = myWidget.get("foo"); 5 6 // set the value of "foo" 7 myWidget.set("foo", someValue);
标准可以让其他挂件与控制代码以统一的方式与一个挂件交互,给你了一中当一个字段被访问的添加自定义逻辑的能力(好比修改DOM片段),也可以停止其他方法(如事件处理器或通知)。例如,你的挂件有个自定义的value,你想在它被改变的时候通知什么人(通过一个你定义的onChange方法):
1 // assume our field is called "value" 2 3 _setValueAttr: function(value) { 4 this.onChange(this.value, value); 5 this._set("value", value); 6 }, 7 8 // a function designed to work with dojo/on 9 onChange: function(oldValue, newValue) {}
正如你说看到的,这在我们的挂件中给了我们自定义getter与setter的行为一个方便的方式。
Owning handles(拥有处理器)
/*不太理解,学学其他的回头再译*/
预定义的属性与事件
最后,_WidgetBase提供一个预定义属性的集合:
- id: 一个唯一的字符串标识挂件
- lang: 一个很少使用的字符串,可以覆盖Dojo默认的语言
- dir: 支持支持阅读方向
- class: 挂件的domNode节点的class属性
- style:挂件的domNode节点的style属性
- title:挂件的HTTP title属性
- baseClass:挂件CSS类的根
- srcNodeRef:如果有提供的话,在挂件化之前的DOM节点。注意依赖与类型的挂件(如模版挂件),将会随着postCreate被取消,原始的节点被遗弃。
结论
Dijit的_WidgetBase基础架构为创建和使用挂件提供了坚实的基础;可谓面面俱到(生命周期,DOM节点引用,getters与setters,预定义的属性与事件)。我们明白了在开发自定义挂件的生命周期中postCreate的重要性,以及编程方式实例化挂件时需要调用startup方法。我们还覆盖了Dijit的getter/setter基础架构,与挂件domNode属性的重要性。