感谢 yunfengcheng 老师的视频,让我感受到了 Ext 4 的巨大魅力。这两天在跟随视频研究Ext的MVC做练习,结果遇到了一些奇怪的问题。
使用 Ext.Loader 与 Ext.application 的方式加载 MVC 的各个 js 文件时,总是出现两个问题: c is not a constructor 与 item is no define 。经过反复跟踪研究发现,问题出现在了对 Ext.define 、 Ext.create 以及 xtype 的理解不够到位。
1. 首先考虑如何定义一个 js 类,这个 js 类中需要用到别的类的‘对象’:
可以有如下写法:
Ext.define("Ax.home.myComputer",{
extend:'Ext.xxx.xxx',
....
items:[
Ext.create('Ax.home.ComputerForm', {}),
Ext.create('Ax.home.ComputerWindow', {})
],
...
});
2. 这种写法在通用逻辑上貌似是没有错的。然而,在执行 Ext.define 函数的时候,就会根据items配置实例化 items 中对象。这就不对了。因为 ‘Ax.home.myComputer’ 类的对象在创建的时候才需要实例化其中的成员。 而不应该在其定义的时候实例化其成员。而如上做法就违背了这样一个基本原则。
而违背这样一个原则所带来的后果是什么呢?
1) 如果 Ax.home.ComputerForm 与 Ax.home.ComputerWindow 采用 MVC 模式分别被保存到了其他的 js 文件中。那么,这些文件会被动态加载进来,而就目前我所观察的结果,MVC 中 controller 中的 views、stroes、models 所定义的内容,在运行时,其加载顺序不定!如果是如此的话, 那么假如 Ax.home.myComputer 先于其依赖的两个文件 Ax.home.ComputerForm 与 Ax.home.ComputerWindow 加载的话, 那么Ext.define("Ax.home.myComputer",{...}); 中的Ext.create就会出错。会导致 item is no define 错误。 而如果使用 grid 中的 store 配置的话 会导致 c is not a constructor (其中 c 被追出来是 column 对象)。
2) 发现Ext的define 会将定义的类一次性加载到内存中,并且建立了一个类和对象管理器来统一管理所有类与对象。如果第一次define运行时出现如上错误的话,将导致define的整个类在以后的生命周期中都是巨大的错误。
3) 即便是侥幸define创建成功了这个类,但是这个类中的 成员 items 中的内容会不会 只有一个副本呢?根据 Ext 的类管理器推理,可能会是(这还得多研究才是)。如果是的话,那就麻烦了!本不应该成为静态成员的,结果变成了静态成员!
3. 那么,该如何解决这个问题呢?
如果只是想表面上解决这个问题,让其运行通过,那么就极力的调整Js类文件的加载顺序呗!可这很麻烦!
如果想根本解决这个问题的话呢?最后发现 xtype 就可以!
1) 在定义基础类 A 的时候, 加上 alias 属性,给该类型定义一个别名;
2) 在定义新类型 B (其中使用到A), 则使用 xtype 属性,使用 A 的别名,就OK。
那么我们回头来看,无论类文件加载顺序如何,只要最终都被加载上来,那么,当执行Ext.define("Ax.home.myComputer",{...}); 时,不会根据 xtype 的配置去创建对象。而只是将其加入到自身的 xtype 属性中。直到调用 Ext.create 的时候,才会根据 xtype 所指定的别名,到Ext的别名管理器中寻找所需要的类。
这样做可以说很好的符合了设计中面向接口而非实现的基本原则,则很好的避免了如上的问题。
…………………………………………………………………………………………………………………………………
这样定义本身就是不合理的,不管用create还是xtype, 对于创建自定义类型, 如果是component的定义item 到initComponent函数,不是component的定义到constructor中去。 例子: Ext.define("Ax.home.myComputer",{ extend:'Ext.xxx.xxx', initComponent : function() { this.items = [ {}]; Ax.home.myComputer.superclass.initComponent.apply(this, arguments); } }); |