Ext架构分析(4)--Container之旅

 BoxComponent继承了Component,主要是实现了设置组件的宽度、高度以及位置(相对于容器或相对于document.body),他的实现较为简单,需要注意的是:
    1.BoxComponent可以通过resizeEl属性设置进行调整大小的对象,positionEl属性设置调整位置的对象,并且在render事件中进行设置,将属性封装为Ext.element对象;
    2.setSize和setPosition方法是在afterRender事件中被触发的,换句话说,组件调整位置和大小是在渲染后进行的。 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅onRender : function(ct, position)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext.BoxComponent.superclass.onRender.call(
this, ct, position); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(this.resizeEl)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅  
this.resizeEl = Ext.get(this.resizeEl); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(this.positionEl)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅  
this.positionEl = Ext.get(this.positionEl); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅}

Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅afterRender : 
function()Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext.BoxComponent.superclass.afterRender.call(
this); 
Ext架构分析(4)--Container之旅
this.boxReady = true
Ext架构分析(4)--Container之旅
this.setSize(this.width, this.height); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(this.x || this.y)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅  
this.setPosition(this.x, this.y); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅}
else if(this.pageX || this.pageY)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅  
this.setPagePosition(this.pageX, this.pageY); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅

  Ext.Containr继承了BoxComponent,在他的initComponent方法中,增加了对以下事件的支持: 'afterlayout','beforeadd','beforeremove','add','remove'。
Container主要实现了对layout和items的管理。

  首先,让我们看一下Container对于items的管理:
  你可能会发现大部分的Widget都支持在构建器中传入一个items数组以非常方便的形式构建该Widget的子组件,而该数组大部分情况是由json构成,让我们看个例子:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅new Ext.menu.Menu(Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅id: 
'mainMenu'
Ext架构分析(4)--Container之旅items: [ 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅text: 
'I like Ext'
Ext架构分析(4)--Container之旅checked: 
true,   // when checked has a boolean value, it is assumed to be a CheckItem 
Ext架构分析(4)--Container之旅
checkHandler: onItemCheck 
Ext架构分析(4)--Container之旅}

Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅text: 
'Ext for jQuery'
Ext架构分析(4)--Container之旅checked: 
true
Ext架构分析(4)--Container之旅checkHandler: onItemCheck 
Ext架构分析(4)--Container之旅}

Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅text: 
'I donated!'
Ext架构分析(4)--Container之旅checked:
false
Ext架构分析(4)--Container之旅checkHandler: onItemCheck 
Ext架构分析(4)--Container之旅}
'-'Ext架构分析(4)--Container之旅 

Ext架构分析(4)--Container之旅

那么,这些json对象看不到表示任何对象类型的属性(xtype),Widget是怎样正确解析这些json对象的呢? 魔术就发生在Container中,首先,在Container的构建器中,有如下的语句:
Ext架构分析(4)--Container之旅var items = this.items;//如果传递了items对象 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(items)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
delete this.items; 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(items instanceof Array)Ext架构分析(4)--Container之旅{//items对象可以是数组,也许这样写更清楚些:this.add(items) 
Ext架构分析(4)--Container之旅
this.add.apply(this, items); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅}
elseExt架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
this.add(items); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅

实际上,大多Widget都有自己的缺省的add的实现以满足自身的要求,Container也提供了一个缺省的add方法的实现如下:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅add : function(comp)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(!this.items)Ext架构分析(4)--Container之旅{//如果未实现items数组,创建items数组 
Ext架构分析(4)--Container之旅
this.initItems(); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
var a = arguments, len = a.length;//如果传入的是数组则对每个元素进行递归调用add方法 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(len > 1)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
for(var i = 0; i < len; i++Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
this.add(a); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
return
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
//this.applyDefaults(comp)方法对元素设置了缺省属性,注意到此时为止,还没有生成相应的组件,现在的item对象依然还是一个简单的json对象。lookupComponent方法则会生成元素组件 
Ext架构分析(4)--Container之旅
var c = this.lookupComponent(this.applyDefaults(comp));   
Ext架构分析(4)--Container之旅
var pos = this.items.length; 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(this.fireEvent('beforeadd'this, c, pos) !== false && this.onBeforeAdd(c) !== false)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
this.items.add(c); 
Ext架构分析(4)--Container之旅
//把每个子元素的ownerCt设置成Container自己 
Ext架构分析(4)--Container之旅
c.ownerCt = this
Ext架构分析(4)--Container之旅
//触发add事件 
Ext架构分析(4)--Container之旅
this.fireEvent('add'this, c, pos); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
return c; 
Ext架构分析(4)--Container之旅}

Ext架构分析(4)--Container之旅

让我们看一下lookupComponent方法的实现:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅lookupComponent : function(comp)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(typeof comp == 'string')Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
//如果传入的是字符串,进行查找 
Ext架构分析(4)--Container之旅
return Ext.ComponentMgr.get(comp); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅}
else if(!comp.events)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
//如果是对象,但不是继承自Observable的对象(在这里,即不是Widget组件对象),则新建一个对象,这就是我们前面讨论的情况,传入的是配置数组。 
Ext架构分析(4)--Container之旅
return this.createComponent(comp); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
return comp; 
Ext架构分析(4)--Container之旅}

魔术的答案在这里,createComponent 方法的实现:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅createComponent : function(config)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
//this.defaultType是"panel",Container缺省实现是根据传入的json对象创建相应的panel 
Ext架构分析(4)--Container之旅
return Ext.ComponentMgr.create(config, this.defaultType); 
Ext架构分析(4)--Container之旅}

而ComponentMgr的create方法的实现也很简单:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅create : function(config, defaultType)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
return new types[config.xtype || defaultType](config); 
Ext架构分析(4)--Container之旅}
 

最终,秘密揭晓,Container的缺省实现将根据传入的items数组中的每个item的xtype属性进行子元素的创建。如果在item中未指定xtype,则根据配置创建panel.

Ext.Container除了通过add()方法,还提供了insert(),remove()等方法实现了对items的维护。在item中的每个元素被加入items之前,都调用beforeAdd方法,如果返回值为true,则该元素元素被设置缺省属性(通过applyDefaults方法),并吧ownerCt属性赋为container,然后加入items,并触发add事件。


Container还提供了两个很有用的方法:bubble和cascade。
bubble方法实现了一个方法在父容器中的递归调用,当然,只要方法在任何一个父容器中返回false,则调用被终止;
cascade方法则实现了方法在容器的子元素中被调用;
需要指出的是,如果未设置任何layout,则container返回ContainerLayout:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅getLayout : function()Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(!this.layout)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
var layout = new Ext.layout.ContainerLayout(this.layoutConfig); 
Ext架构分析(4)--Container之旅
this.setLayout(layout); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
return this.layout; 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅


让我们再看一下对于layout的管理,通过render方法,Container设置了layout对象并调用了doLayout方法:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅render : function()Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅    Ext.Container.superclass.render.apply(
this, arguments); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅  
if(this.layout)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅      
if(typeof this.layout == 'string')Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅        
this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); 
Ext架构分析(4)--Container之旅      }
 
Ext架构分析(4)--Container之旅      
this.setLayout(this.layout); 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅      
if(this.activeItem !== undefined)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅          
var item = this.activeItem; 
Ext架构分析(4)--Container之旅          
delete this.activeItem; 
Ext架构分析(4)--Container之旅          
this.layout.setActiveItem(item); 
Ext架构分析(4)--Container之旅          
return
Ext架构分析(4)--Container之旅      }
 
Ext架构分析(4)--Container之旅  }
 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅  
if(!this.ownerCt)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅      
this.doLayout(); 
Ext架构分析(4)--Container之旅  }
 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅  
if(this.monitorResize === true)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅      Ext.EventManager.onWindowResize(
this.doLayout, this); 
Ext架构分析(4)--Container之旅  }
 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
doLayout方法则调用自己的layout对象的layout方法并遍历items中的元素,逐个调用layout方法:
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅if(this.rendered && this.layout)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅    
this.layout.layout(); 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅
if(this.items)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅    
var cs = this.items.items; 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅    
for(var i = 0, len = cs.length; i < len; i++Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅      
var c = cs; 
Ext架构分析(4)--Container之旅Ext架构分析(4)--Container之旅      
if(c.doLayout)Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅          c.doLayout(); 
Ext架构分析(4)--Container之旅      }
 
Ext架构分析(4)--Container之旅  }
 
Ext架构分析(4)--Container之旅}
 
Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅
Ext架构分析(4)--Container之旅

上一篇:Bootstrap教程(15)--警告框、弹出框、工具提示框


下一篇:Spark MLlib - Decision Tree源码分析