在找网上找了一下关于这个函数的大致介绍:
提供一个页面中所有组件的一个注册表( Ext.Component 的实例,或者任何子类),这样可以通过 component id 方便此访问它们 此对象也提供了可用Componentclasses的一个注册表 ,以便于记忆的字符串为key,叫做Component的 xtype. xtype . 当创建一个完整的、包含配置项的对象时,它为一个完全使用Ext的页面 提供了一种避免实例化子组件方法。子组件可以被简单指定为一个配置对象 ,只要指定正确的xtype ,这样当Component需要渲染时, 可以找到正确的类型进行懒初始化。
今天在分析Ext.form.FormPanel组件,在一地方卡了很长时间,其中就涉及到Ext.ComponentMgr。特在这里记下,免得以下又会被卡住,也希望看到此篇文章的同行有所收获
<script type="text/javascript">
Ext.onReady(function () {
var panel = new Ext.form.FormPanel({
renderTo: 'formPanel',
width: 400,
height: 500,
layout: "form",
items: [{
xtype:'fieldset',
columnWidth: 0.5,
title: 'Fieldset 1',
collapsible: true,
autoHeight:true,
defaults: { anchor: '-20' // leave room for error icon },
items: [
{xtype:'customType-0', fieldLabel: 'Field 0' },
{ xtype:'customType-1', fieldLabel: 'Field 1' },
{ xtype:'customType-2', fieldLabel: 'Field 3' }
]
}]
});
}); </script>
![2011031617401919.png](https://i-blog.csdnimg.cn/blog_migrate/6c68c19e13781b14cb6c75ee51821dac.png)
图(1)FormPanel类的继承结构图
当实例化FormPanel则会调用Ext.Component的constructor,如果你不知道为什么,可以先看下之前的文章就会明白.当调用Ext.Component的constructor时候
Ext.Component = function(config){
//...
this.initComponent();
//...
}
this.initComponent将会调用FormPanel的initComponent,这将会沿着FormPanel的继承链一直向上回溯至Ext.Component 的initComponent方法,在这一系列调用initComponent方法的过程之中我们将目光锁定到Ext.Container的initComponent方法
Ext.Container = Ext.extend(Ext.BoxComponent, {
//...
initComponent:function(){
//...
var items = this.items;
if(items){
delete this.items;
this.add(items);
}
},
add : function(comp){
this.initItems();
var args = arguments.length > 1;
if(args || Ext.isArray(comp)){
var result = [];
Ext.each(args ? arguments : comp, function(c){ result.push(this.add(c)); }, this);
return result;
}
var c = this.lookupComponent(this.applyDefaults(comp));
//...
},
applyDefaults : function(c){
//...
},
lookupComponent : function(comp){
if(Ext.isString(comp)){
return Ext.ComponentMgr.get(comp);
} else if(!comp.events){
return this.createComponent(comp);
}
return comp;
}, createComponent : function(config, defaultType){
if (config.render) {
return config;
}
var c = Ext.create(/*省略*/);
//...
}
//...
});
当调用Ext.Container的initComponent方法时候,将会牵扯到一系列的方法的调用,代码如上
当最开始调用this.add(items)时,此时的this的可执行上下文环境是panel( var panel=new Ext.form.FormPanel(/* ... */); ),此时items的xtype为fieldset
![2011031617445264.png](https://i-blog.csdnimg.cn/blog_migrate/abc9beff31bfda07e8b2ae687cf0c2e3.png)
图(2)
接下来进入到Ext.Container的add函数中Ext.isArray(comp)显示是成立的,从图(2)就能看得出来。接下是Ext.each方法调用result.push(this.add(c))将会递归调用add
方法
![2011031617464873.png](https://i-blog.csdnimg.cn/blog_migrate/b9d059e1346ed8f140ec3b2e6e44bbda.png)
图(3)
接上面,当递归调用add时传的参数截图如图(3) if(args||Ext.isArray(comp)){/* ...*/} 很显然不会执行,这样程序就执行到 this.lookupComponent(this.applyDefaults(comp)), 执行this.lookupComponent(/* ... */)方法,Ext.isString(comp)返回false 因为comp是object,因此将调用this.createComponent(comp),进入到方法。我们把目光锁定到Ext.create方法上,由于Ext.create = Ext.ComponentMgr.create 下面是这个函数的源码
Ext.ComponentMgr = function(){
//...
return {
create : function(config, defaultType){
return config.render ? config : new types[config.xtype || defaultType](config);
}
//...
};
}()
看上面的代码出现了new,当返回的时候this的可执行上下文环境就发性了变化,将不再是之前的panel了,而是新创建的Fieldset。当递归调用结束返回到Ext.Component中的this.add(items)时候,由于this的可执行上下文环境发现了变化,此时items截图如下
![2011031617491211.png](https://i-blog.csdnimg.cn/blog_migrate/e0ab2c261ea6fd7528d679a17e16ae8b.png)
图(4)
从又会重复之前的动作。
![2011031617503178.png](https://i-blog.csdnimg.cn/blog_migrate/26645b32834ce1232a5a8e735d33b606.png)
图(5)
IE提示出现以上错误,crtl+G快速定位到10462行
![2011031617514454.png](https://i-blog.csdnimg.cn/blog_migrate/8b048c1093769a9999487bb028e067d6.png)
图(6)
用VS调试
![2011031617524892.png](https://i-blog.csdnimg.cn/blog_migrate/b911e69fea0f8c73e2a4703931fe3c5d.png)
图(7)
以上是new types[/* ...*/](config)中的types的一部分截图,而此时config.xtype为"customType-0" 在types中没有,理所当然要报错,因为自己打算写相应的扩展,故用了xtype分别为"customType-0","custom-1","custom-2"。看到types数组中有许多项,我在Ext.ComponentMgr函数翻了半天,就是不明白这么多项是怎么来的,百思不其解???
Ext.ComponentMgr = function(){
var all = new Ext.util.MixedCollection();
var types = {};
var ptypes = {};
return {
//...
all : all,
types : types,
ptypes: ptypes
//...
}
}();
看到Ext.ComponentMgr函数后面的括号,想到该函数在加载之后会立刻执行。以下是该函数执行完之后的截图
![2011031617554976.png](https://i-blog.csdnimg.cn/blog_migrate/ed0d1a4d173d76dbc42a31552914ba07.png)
图(8)
执完该函数完之后,types中一项也没有,感觉太奇怪了,继续单步调试下去到了 Ext.reg('component', Ext.Component);
因为 Ext.reg = Ext.ComponentMgr.registerType;
Ext.ComponentMgr = function(){
//...
return {
//...
registerType : function(xtype, cls){
types[xtype] = cls;
cls.xtype = xtype;
}
//...
};
}();
看到这个registerType函数之后,一下子就明白了 当执行完 Ext.reg('component', Ext.Component);
![2011031617580162.png](https://i-blog.csdnimg.cn/blog_migrate/4c24fd7b402e2f24cf892ed0692e3295.png)
图(9)