YUI3学习(七)---组件框架之 Base
Base组件
Base被设计为那些衍生自Attribute和EventTarget的类的底层基础类。
为创建基于Attribute的对象提供标准模板,也为类的层次提供了一致的init()和destory()方法序列来串联初始化(initializer)和销毁(destructor)方法。
Base同时也通过plugins或extensions机制为类提供了代码重用的方法。
对应模块‘base‘, Base uses Attribute,Plugin.Host
?
使用Base的功能
1,扩展Base
Base作为实现了Attribute及EventTarget功能的基类,具有了Attribute配置及相关的事件注册功能,通过extend可以创建Base的子类
?
YUI().use("base", function(Y) { function MyClass(config) { MyClass.superclass.constructor.apply(this, arguments); } Y.extend(MyClass, Y.Base, { // Prototype methods for your new class });});Base的构造器函数支持接收一个字面量对象,可以在构造过程中用来设置属性的初始值。此外还接受事件和插件相关的参数,具体参考Base API
??
?
2,静态属性
Base需要两个静态的属性:NAME, ATTRS 。当设置事件或属性的时候会用到这两个属性。
示例如下:
?
function MyClass(config) { MyClass.superclass.constructor.apply(this, arguments);}MyClass.NAME = "myClass";MyClass.ATTRS = { A : { // Attribute "A" configuration }, B : { // Attribute "B" configuration }}Y.extend(MyClass, Y.Base, { // Prototype methods for your new class});?
NAME属性
用来标识类,它的用途是作为该类对象发布事件的前缀,如上例MyClass类实例发布事件要采用’myClass:'前缀。默认的约定的采用类名的驼峰拼写。
事件前缀保证了类事件的可识别性。为不同了类的同名事件提供了一种隔离机制。实际上在定义NAME属性前提下,如果在触发时不写前缀也同样可以触发事件。
为了保证代码的清晰,最好为按约定定义NAME并为自定义的类事件标记前缀!
下面的两个事件注册都会触发。
?
function MyClass(config){MyClass.superclass.constructor.apply(this,arguments);}MyClass.NAME = 'myClass';MyClass.ATTRS = {a:{value:'aa'}};Y.extend(MyClass,Y.Base,{say:function(){this.fire('myClass:enabled');}});var o = new MyClass();o.on('enabled',function(e){alert("enabled")});o.on('myClass:enabled',function(e){alert('myClass:enabled')})o.say();??
NAME属性还会在Base的toString默认实现中使用。
?
ATTRS属性
ATTRS属性是一个关联数组,为继承自Base的类提供默认的属性定义并添加到类的实例中。类实例将包含类层次结构中定义的所有属性。
属性由属性名和属性值配置组成,如下是Drag类的部分属性配置
?
Drag.ATTRS = { node: { setter: function(node) { var n = Y.one(node); if (!n) { Y.fail('DD.Drag: Invalid Node Given: ' + node); } return n; } }, dragNode: { setter: function(node) { var n = Y.one(node); if (!n) { Y.fail('DD.Drag: Invalid dragNode Given: ' + node); } return n; } }, offsetNode: { value: true }, clickPixelThresh: { value: DDM.get('clickPixelThresh') }, ...};?
更多关于属性的配置可参考 属性配置参数列表
?
当初始化一个衍生自Base类的子类时,Base的init()方法会初始化类层级中每一个类的ATTRS定义的属性信息。这避免了每个类在constructor/initializer中重复定义属性初始化代码。
此外,Base定义了属性的初始化顺序:Base->子类。在ATTRS属性初始化过程中,如果一个属性用到后面定义的属性,后面的属性会按照需要进行初始化。
值得注意的是,Base考虑到性能的因素,默认采用懒加载方式初始化属性。也就是说知道调用该属性的时候才会被初始化。在Attribute介绍属性配置的时候提过lazyAdd配置属性,可以通过设置lazyAdd为false修改默认的惰性行为。
?
3,初始化(initialization)和销毁(destruction)
Base实现了final类型的init()和destory()两个方法来建立生命周期中初始化和销毁两个阶段。
Base的子类可以通过定义原型链上的initializer()和destructor()方法实现初始化和销毁的生命周期管理,Base通过init()和destory()方法遍历原型链来调用。
每个Base子类不需要调用父类的方法实现,Base会根据类层次按固定的顺序调用。
?
Y.extend(MyClass, Y.Base, { // Prototype methods for your new class // 该方法会在init()初始化过程中被调用 initializer : function(cfg) { this._wrapper = Y.Node.create('<div name="code">var overlay = new Y.Overlay({ srcNode: "#module", plugins : [{fn:AnimPlugin, cfg:{duration:2}}]});此外,如果组件开发者希望在组件类定义时默认增加一些插件功能,可以使用Base.plug和Base.unplug方法。
?
关于Plugin的开发,可参考Plugin介绍, The Widget IO Plugin, Overlay IO Plugin and Overlay Animation Plugin 都是学习插件开发的好例子。
YUI官方给出了定义插件的模板文件:http://developer.yahoo.com/yui/3/plugin/assets/myplugin.js.txt
?
5,扩展Extensions
Base提供了一个静态的build方法,通过将一个主类和一个或多个扩展类组合来创建自定义类。与插件相似,它们把特定功能的实现封装在扩展类中。
不同的是,扩展是在类级别扩展类,创建新类;而插件则是在实例级别扩展实例。
build()方法可以将已经存在的主类与几个扩展类组合(mix)来创建新类。为新类增加来自扩展类的方法、属性和事件等。默认情况下,
build方法不会影响主类,并未为主类增加额外的功能;但是可以在需要的情况下通过配置选项是否影响主类。
?
/* Main Class */function Panel(cfg) { Panel.superclass.constructor.apply(this, arguments);}Panel.ATTRS = { // Panel attributes close : { ... }, minimize : { ... }, shadow : { ... }, ...};Y.extend(Panel, Y.Base, { // Panel methods show : function() { ... }, hide : function() { ... }, minimize : function() { ... }};/* Additional Resizable Feature */function Resizable() { this._initResizable();}Resizable.ATTRS = { handles : { ... }, constrain : { ... }};Resizable.prototype = { _initResizable : function() { ... } lock : function() { ... }};/* Additional Modality Feature */function Modal() { this._initModality();}Modal.ATTRS = { modal : { ... }, region : { ... }};Modal.prototype = { _initModality : function() { ... }, showMask() : function() { ... }, hideMask() : function() { ... }};//创建新类WindowPanel,继承自Panel,并扩展Resize和Modal类的方法和属性。var WindowPanel = Y.Base.build("windowPanel", Panel, [Resizable, Modal]);var wp = new WindowPanel({ shadow: true, modal: true, handles:["e", "s", "se"]});wp.show();wp.lock();YUI官方给出了实现扩展的模板文件:http://developer.yahoo.com/yui/3/base/assets/myextension.js.txt
?
build方法内部实现:
1,继承主类创建新的类;
2,将所有扩展类的prototype方法扩展(augment)到主类中。
3,为新类合并(aggregate)所有已知的静态属性。 除了ATTRS里的属性,需要合并的其他静态属性标记在类的_buildCfg.aggregates定义中。
例如:除了Base定义了ATTRS属性,Widget的_buildCfg.aggregates中添加的HTML_PARSER属性也会被合并到新类。
?
当新类实例化时,在init阶段,新类的构造器将调用主类的构造器。
?
除了build静态方法,Base还提供了的create和mix静态方法实现扩展。
Base.create()
该方法可以传入额外的原型方法和静态属性。
Base.mix()
该方法可以在现有类上直接添加扩展类的方法。也就是上面提到的改变主类的实现方法。
以下是部分源码,从中可以了解三种方法的不同作用。具体说明请参看Base API。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
Base.build = function(name, main, extensions, cfg) { return build(name, main, extensions, null, null, cfg); };Base.create = function(name, base, extensions, px, sx) { return build(name, base, extensions, px, sx);};Base.mix = function(main, extensions) { return build(null, main, extensions, null, null, {dynamic:false});};???
?
?
?
?
?
?
?
?