ExtJS学习之路第三步:理解引擎之下,ExtJS4中的类
写写就发现,有些代码不查查源头,不明白是怎么回事?搜到这篇文章觉得还是收益匪浅,更容易读懂代码。
Classes in Ext JS 4: Under the hood
Countdown to Ext JS 4: Dynamic Loading and New Class System[官网]
整理如下:
简单回顾一下,新的Class System (类系统),使我们能够这样定义类:
Ext.define('Ext.Window', { extend: 'Ext.Panel', requires: 'Ext.Tool', mixins: { draggable: 'Ext.util.Draggable' }, config: { title: "Window Title" } });
这里,我们建立一个Ext.Window类的稍微简化版本。设置Window是Panel的子类,宣称需要Ext.Tool类,以及混合Ext.util.Draggable类的的某些功能。
让我们一句一句分析。'extend'声明你所期望的--Window必须是Panel的子类。
'requires'声明意味着命名类-Ext.Tool必须在Window类被视为可用之前[即将用]就已经存在。如果你用SeaJS的require话就明白时机啦,简单说就是Window要应用了,Ext.Tool必须在。
'mixins'这个在SASS(CSS预处理器)中有应用。在ExtJS4中,'minxin'(混合声明)是个全新的概念。一个mixin仅仅是一组函数(有时候是一组属性)被合并成到一个类中。比如,Ext.util.Draggable类中有个'startDragging'的功能,这就被复制到Window类中,我们能在Window的实例中应用'startDragging'功能。
定义startDragging方法:
Ext.define('Ext.util.Draggable', { startDragging: function() { console.log('started dragging'); } });
实例化
var win = Ext.create('Ext.Window'); win.startDragging(); //"started dragging"
当一个类需要继承多个特性时,Minins就非常有用啦!而这对传统的单继承机制来说不易。例如,Ext.Windows是一个可拖动的组件,比如有Sliders,Grid headers和其他非常多的UI元素。因为这种动作发生在不同的地方,把这种拖拽行为归到单独一个父级类是不可行的。因为并非所有这些UI元素都以个共同的父级类。创建一个可团拽的Minxin解决了这个问题,仅需几行代码现在任何元素都可以变为可拖动的。
最后一个新的功能块,是'config'配置。ExtJS中的大多数类都需要配置参数,其中很多在运行时改变。上面的例子中,我们声明了Ext.Window有个'title'配置,默认值是'Window Title'。通过上面的这种设置,我们免费得到4种方法,getTtiel,setTitle,resetTitle,applyTitle.
getTitle – 返回当前title值
setTitle – 设置新的title
resetTitle – 重置title值,此处为'Window Title'
applyTitle – 这是一个模板方法,你可以选择定义。当setTitle触发的时候,applyTitle触发。
applyTitle功能是当title改变时,调用其它需要改动的逻辑。比如:当更换一个title的时候我们可能想更新某个DOM元素。
Ext.define(‘Ext.Window’, { //..as above, config: { title: 'Window Title' }, //updates the DOM element that contains the window title applyTitle: function(newTitle) { this.titleEl.update(newTitle); } });
这种方式节省了大量的时间和代码,同时提供所有configuration配置选项一致的API-双赢。
深入研究
为了实现这神奇的功能,ExtJS 4引入4个新类。
Ext.Base-所有的类都继承自Ext.Base.它为所有类提供基本的低级别的功能。
Ext.Class-产生新类的工厂。
Ext.ClassLoader-负责确认class可用,如果页面上不存在,加载他们。
Ext.ClassManager-揭开类创建的序幕和管理依赖关系
这些在幕后齐心协力,大部分时间当你定义和使用类的时候,你不需要知道什么被调用了。常用的两个方法是Ext.define和Ext.create,在引擎中都触发Ext.ClassManager,这反过来又利用其它三个类把一切融合在一起。
Ext.Class和Ext.Base的区别是非常重要的。Ext.Base是顶层的父类,它定义了每个类,每个类都继承自Ext.Base在某些时候。Ext.Class代表类本身,每一个你定义的类都是Ext.Class的实例,并且是Ext.Base的子类。
为了说明这一点,假设我们创建MyClass的类,它并不扩展其他类。
Ext.define('MyClass', { someFunction: function() { console.log('Ran some function'); } });
MyClass的直接父类是Ext.Base,因为我们并没有扩展其他。
类的继承层次中,根始终是Ext.Base,也就是说每个类始终都是继承自Ext.Base.所以每个类是Ext.Base的子类,是Ext.Class的实例。这就意味着在之后很容易修改类,比如混合附加功能
//可以在定义类的时候就增加混合功能 Ext.define('MyClass', { mixins: { observable: 'Ext.util.Observable' } }); //也可以在类定义之后增加 MyClass.mixin('draggable', 'Ext.util.Draggable');
这种架构开辟了都动态创建类和元编程的新的可能性,这在早期版本是非常困难得。