理解 _WidgetBase

理解 _WidgetBase

Understanding _WidgetBase

In this tutorial, you'll learn what Dijit's _WidgetBase module is, and how it serves as the foundation for all widgets in the Dojo Toolkit.

在本教程中,你将会学习 Dijit包中的_WidgetBase模块,它是Dojo 框架所有微件的基础。

Getting Started

开始

The foundation of Dijit, and the ability to create your own widgets, relies primarily on one base class, defined in the dijit/_WidgetBase module. While there are a few other key pieces commonly relied upon for developing web applications with the Dojo Toolkit (such as the Dojo parser and the Dijit templating system), this module is the key to creating any kind of custom widget using the Dojo Toolkit. In this tutorial, you'll learn how Dijit's widget infrastructure works.

Dijit的基础以及实现创建自定义微件,主要依赖于一个定义在 dijit/_WidgetBase中的模块。当然在使用Dojo框架开发应用时还有一些其他的通用的依赖(例如Dojo parser和 Dijit 模板系统),这个模块是使用Dojo框架创建任意类型自定义微件的关键。在本教程中,你将会学到Dijit包的微件基础是如何工作的。

If you are coming from a previous version of Dojo, you may be familiar with the dijit/_Widget module. While dijit/_Widget still exists and inherits from dijit/_WidgetBase, it is currently recommended to inherit from dijit/_WidgetBase directly when defining your own custom widgets from the ground up. dijit/_Widget is likely to be phased out by Dojo 2.0.

如果你是Dojo老版本的用户,你可能会比较熟悉dijit/_Widget模块,dijit/_Widget模块在新版本中依然存在,并且也继承自dijit/_WidgetBase,如果你要从头开始创建你自己的自定义模块,新版本的Dojo建议直接继承dijit/_WidgetBase。dijit/_Widget 可能会在Dojo2.0中删除。

The most important thing to understand about Dijit's system is the lifecycle of a widget. This lifecycle is primarily concerned with the inception of a widget—in other words, from when a widget is conceived to when it is fully usable by your application—through the destruction of a widget and its associated DOM elements.

理解Dijit体系最重要的概念就是微件的生命周期。生命周期主要关心微件的初始化-也就是,从微件开始构造到在程序中完全可用-直到微件及其关联的Dom元素被销毁。

If you are wondering why "_" is in front of both "Widget" and "WidgetBase", it is because neither module is intended to be instantiated directly; instead, they are intended to be used as base classes using the Dojo Toolkit's declare mechanism.

你可能会想为什么“Widget”和“WidgetBase”前面都带一个“_”,因为这两个模块都不能直接的实例化,也就是说,只能用用Dojo的decalre语句作为其他微件的基类使用。

To accomplish this, dijit/_WidgetBase defines two concept lines: a set of methods that are called in succession during the process of creation, and a way of getting/setting fields with minimal data binding while the widget lives in the application. Let us take a look at the first mechanism: Dijit's widget lifecycle.

为了实现这一功能,dijit/_WidgetBase 定义了两个概念:在微件创建的过程中,会调用一系列的成功执行回调方法;在微件运行期间可以通过getting/setting 属性字段来绑定少量数据。 我们先来看一下第一个机制:Dijit 微件的生命周期。

The Dijit Lifecycle

Dijit的生命周期

Each widget declared with _WidgetBase as its base will run through several methods during instantiation. They are listed here, organized according to the sequence in which they are called:

每个继承自_WidgetBase的微件在初始化时都会自动调用一些方法。这些方法如下所示,所列顺序即它们被调用的顺序。

  • constructor (common to all prototypes, called when instantiated)
  • constructor(所有原型都有,在初始化时调用)
  • postscript (common to all prototypes built using declare)
  • postscript (所有原型都有,使用declare创建)
    • create
      • postMixInProperties
      • buildRendering
      • postCreate
  • startup

View Demo

These methods exist to handle a number of things:

这些方法用来解决以下问题:

  • initialize widget data from both default and run-time values
  • 初始化微件的默认及运行时数据
  • generate the DOM structure for the widget's visual representation
  • 生成微件的Dom元素结构
  • place the widget's DOM structure within the page
  • 将微件的Dom元素结构加载到页面上
  • handle logic that is dependent on the DOM structure being present in the document (such as DOM element dimensions)
  • 处理Dom元素在页面中的结构逻辑(例如Dom元素的大小)
postCreate()
postCreate()方法

By far, the most important method to keep in mind when creating your own widgets is the postCreate method. This is fired after all properties of a widget are defined, and the document fragment representing the widget is created—but before the fragment itself is added to the main document. The reason why this method is so important is because it is the main place where you, the developer, get a chance to perform any last-minute modifications before the widget is presented to the user, including setting any kind of custom attributes, and so on. When developing a custom widget, most (if not all) of your customization will occur here.

到目前为止,你要牢记的 在创建自定义微件过程中最重要的方法就是postCreate方法。这个方法在微件所有属性定义完成之后执行,表明页面元素部分已创建,不过还没添加到主页面上。这个方法之所以如此重要是因为,它给你,开发者,在微件呈现给用户之前最后修改微件的机会,包括设置任意的自定义属性等等。当开发一个自定义微件时,大部分(如果不是全部的话)的自定义内容都出现在这里。

startup()
startup()方法

Probably the second-most important method in the Dijit lifecycle is the startup method. This method is designed to handle processing after any DOM fragments have been actually added to the document; it is not fired until after any potential child widgets have been created and started as well. This is especially useful for composite widgets and layout widgets.

startup大概要算Dijit生命周期中第二重要的方法了。这个方法用来在Dom元素被实际添加到页面之后做一些处理;这个方法在微件所有的可能的子微件被创建并完成启动之后才会执行。这对于复合微件及布局微件尤其重要。

When instantiating a widget programmatically, always call the widget's startup() method after placing it in the document. It's a common error to create widgets programmatically and then forget to call startup, leaving you scratching your head as to why your widget isn't showing up properly.

通过代码创建微件时,总是要在微件加载到页面后调用其startup()方法。通过代码创建微件后忘记调用其startup是一个常见的错误,使我们因微件不能正常显示而抓耳挠腮。

Tear-down methods
析构方法

In addition to the instantiation methods, dijit/_WidgetBase also defines a number of destruction methods (again listed in the order they are called):

除了初始化方法,dijit/_WidgetBase也定义了一些析构方法(同样按调用顺序列出):

  • destroyRecursive
    • destroyDescendants
    • destroy
      • uninitialize
      • destroyRendering

When writing your own widget, any necessary custom tear-down behavior should be defined in the destroy method. (Don't forget to call this.inherited(arguments)!) Dijit itself takes care of node and most object management for you already (using the aforementioned destruction methods), so you generally don't have to worry about writing custom versions of these methods from scratch.

当构建自定义微件时,所有必须的自定义析构方法都应该定义在destroy 方法中。(不要忘了调用this.inherited(arguments)!)Dijit会帮你解决好节点和对象管理,所以你尽可不用担心创建这些方法的自定义版本需要从头做起。

Although destroy is arguably the central destruction method of any widget, it is advisable to call destroyRecursivewhen explicitly destroying a widget. This ensures the destruction of not only the widget itself, but any child widgets.

尽管destroy方法无疑是微件析构时的核心方法,但是当需要明确回收一个微件时需要调用destroyRecursive。这样保证不仅是微件,其子微件部分也会得到析构。

Node references

A widget is generally some sort of user interface, and it would not be complete without some sort of DOM representation._WidgetBase defines a standard property called domNode, which is a reference to the overall parent node of the widget itself. You can always get a reference to this node programmatically if you need to do something (like move the entire widget around in a document), and it is available by the time the postCreate method is called.

节点关联

微件一般是某种界面元素,无法。_WidgetBase 定义了一个标准的属性domNode,指向微件的父节点。在你需要的时候你可以通过代码获取到这个对象(例如在页面中移动整个微件),这个对象在postCreate调用时就已经可用了。

In addition to the domNode property, some widgets also define a containerNode property. This is a reference to a child node in a widget that may contain content or widgets defined outside of your widget definition, such as within the originating source node of a declaratively-instantiated widget.

除了domNode属性,有些微件也定义了containerNode 属性。这个属性指向微件的一个子节点,这个子节点包含主体内容,或者在微件之外的一个微件区域,比如指向最初的通过声明方式定义的微件。

We'll discuss the importance of the containerNode property in another tutorial; for now, be aware that the property exists and may be defined (most notably, it is defined on all widgets which inherit dijit/_Container).

我们会在别的教程中讨论containerNode的重要性,现在,你只需要知道有这么个属性,可能被定义,即可(通常情况,继承自dijit/_Container的微件都会定义这个属性)。

Getters and Setters

获取设置属性方法

In addition to the startup and tear-down infrastructure, _WidgetBase also provides not only a number of pre-defined properties that all widgets need, but also a way of letting you define custom getters and setters that will work with the standard get and set methods, pre-defined on all widgets. This is accomplished by defining custom "private" methods in your code according to the following pattern:

除了启动和析构,_WidgetBase还包括一些微件需要的预定义属性,以及创建自定义的属性使用标准get、set方法存取的方式,所有微件都可以使用。这个功能通过在微件中添加自定义的private类型的、按照下述方式定义方法实现:

// 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 */ }

If you define custom method pairs in this manner, you can then use the standard get and set methods of _WidgetBase on instances of your widget. For instance, given the above example, you could do this:

如果你按照这样的方式在微件中定义了这样的get、set对,就可以使用微件实例的标准的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);

This standard allows other widgets and controlling code to interact with a widget in a consistent way, while giving you the ability to perform custom logic when a field is accessed (such as modifications to a DOM fragment, etc.), as well as allowing you to fire off any other methods (such as an event handler or a notification). For example, say your widget has a custom value, and you want to be able to notify anyone that that value has changed (possibly via an onChange method you've defined):

这种方式允许其他微件及控制代码与微件以一种一致的方式相互影响,并且使你能够在属性被访问时添加其他逻辑(例如修改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){ }

As you can see, this gives us a convenient way to be able to customize getter and setter behavior within our own widgets.

如你所见,这种方式提供了一种便捷的方式修改微件的get、set方法的行为。

When defining your own widgets, you should create custom getter and setter methods whenever you need to define custom logic behind the retrieval or modification of a custom property. When using your own widgets, you should always use the get() and set() methods for field access, in order to properly communicate with the custom getters and setters. In addition, when defining custom setter methods, you should always use the internal _set method to update internal values, in order to interface properly with the watch functionality from dojo/Stateful, which all widgets inherit.

自定义微件时,如果需要自定义存取自定义属性的逻辑,就需要创建自定义的get、set。在使用自己的微件时,访问属性需要使用标准的get()、set()方法以保证正常的访问自定义的存取器。另外,定义自定义存储器时,需要调用内部的_set方法更改内部值,以使watch方法能正常执行,该方法集成子dojo/Stateful,每个微件都继承了。

Owning handles

拥有事件处理器

The _WidgetBase infrastructure provides a method for registering handles as "owned" by the widget. This should be used for any handles created by the widget, often listeners to DOMNode events setup in postCreate().

_WidgetBase 提供了一种“拥有”事件处理器的方式。为微件添加事件处理器都需要使用这种方式,一般用来监听在postCreate()方法中添加的DOM节点的事件。

The method for attaching handles to a widget is .own(), and its usage is simple:

为微件绑定事件处理器使用.own,用起来很方便:

this.own(
    on(someDomNode, "click", lang.hitch(this, "myOnClickHandler)"),
    aspect.after(someObject, "someFunc", lang.hitch(this, "mySomeFuncHandler)"),
    topic.subscribe("/some/topic", function(){ ... }),
    ...
);

The advantage of using own() in the widget infrastructure is that internally, the widget can keep track of all of its handles, and make sure everything is disconnected and/or unsubscribed when the widget is destroyed—preventing any kind of memory leaks.

使用 own()方法的好处是微件可以跟踪所有的事件处理器,保证在微件销毁时,将所有事件解绑,防止内存泄露。

Pre-defined Properties and Events

预定义属性及事件

Finally, _WidgetBase provides a set of pre-defined properties, with appropriate getters and setters where applicable:

最后,_WidgetBase 还提供了一些预定义属性,包括其标准的存取器:

  • id: a unique string identifying the widget
  • id: 标识微件的String类型的唯一值
  • lang: a rarely-used string that can override the default Dojo locale
  • lang: 很少使用的String值,可以重写Dojo默认的locale
  • dir: useful for bi-directional support
  • dir: 用于双向支持
  • class: the HTML class attribute for the widget's domNode
  • class: 微件domNode的html样式
  • style: the HTML style attribute for the widget's domNode
  • style: 微件domNode的style属性
  • title: most commonly, the HTML title attribute for native tooltips
  • title: 一般表示原生提示的html title属性
  • baseClass: the root CSS class of the widget
  • baseClass:微件的根CSS样式
  • srcNodeRef: the original DOM node that existed before it was "widgetified", if one was provided. Note that depending on the type of widget (e.g. templated widgets), this may be unset following postCreate, as the original node is discarded.
  • srcNodeRef: 微件在微件化之前的原始Dom 节点,如果有的话。注意这个属性与微件的类型有关(如基于模板的微件),并且在postCreate之后可能会被丢弃。

Conclusion

As you can see, Dijit's _WidgetBase infrastructure provides a solid foundation on which to create and use widgets; all aspects of a widget (lifecycle, DOM node references, getters and setters, pre-defined properties and events) are covered out of the box. We've seen how a widget's postCreate() method is the most important lifecycle method when developing custom widgets, and how vital calling startup() is when instantiating widgets programmatically. We've also covered Dijit's getter/setter infrastructure, as well as the importance of a widget's domNode property.

结论

如你所见,_WidgetBase为创建和使用微件提供了坚实的基础;微件的方方面面都已经包括了(生命周期、Dom元素关联,getters和setters,预定义方法和事件)。我们知道了微件的postCreate()方法是微件生命周期中最重要的方法,以及通过代码创建微件时调用startup()至关重要。我们也学习了Dijit的getter/setter框架,以及微件domNode属性的重要性。

Resources

扩展资源
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值