第一章 新特性
extjs 4相对于之前的版本作出了重大的修正。其中包括全新的类系统、新平台的引入、api的修整和加强还有新组件的引入(如新的图表和图形组件)。extjs 4提供更快速、更稳定的用户体验,并且让开发人员更容易上手。
在本章我们将学习到下列内容:
extjs是一个跨浏览器的富互联网应用框架,其ui组件容易上手,并全球已有上百万的开发人员正在使用。
extjs 2.x对 extjs 1.x进行了重大的重构,其中包括重构组件模型构建方式,并伴随着多个已有组件的重构。而extjs 3.x是向后兼容extjs 2.x。
extjs 3.x 及其之前的版本在应用程序展现上布局(layout)这一操作占据了绝大部分的时间。extjs 4对此进行了重大的改进。而最终生成的html标签也有所改进。
对于extjs 4.x sencha团队进行了多达4000个单元测试,测试覆盖率达到90%,从而为大家提供一个更稳定可用的框架。
而包含标准api在内的部分api进行了命名习惯的改进,同时使得部分的配置参数更易于使用。
对于extjs 3.x 如pagingtoolbar,toolbar和spacer均和其他类那样属于widgets包。这些类均可通过全局对象ext来直接访问,如ext.pagingtoolbar等。
但在extjs
4.x所有的类都按功能划分到相应的包和命名空间。如pagingtoolbar、toolbar、spacer和其他与工具栏相关的类都已打包到
toolbar包中,并且该包下面的类均以ext.toolbar为命名空间。而其他类也作出了类似的改动,具体的类命名变化请参看原书的
appendix a,ext js 4 versus ext js 3 class names。
若您想继续沿用extjs 3.x的命名习惯那怎么办呢?extjs
4.x为每个类添加了alternateclassname属性,该属性表示该类的可选命名,也就是extjs
3.x中的类名,如ext.toolbar.pagingtoolbar的alternateclassname属性就是
ext.pagingtoolbar。而在创建组件时采用ext.create(classname或者alternateclassname)即可。当
然还是强力推荐使用extjs 4.x的全新类名。
api文档地址:http://docs.sencha.com/ext-js/4-0
打开文档首先看到的是欢迎页。home,api
documentation,guides,videos和examples几个标签为于文档的左上角。当我们点击api
documentation标签后,所有包的列表会在在左方和中间部分呈现。相关的类会以base、view、components、data和
utilities来分类。当我们点击某个类时效果如下:

在页面的上方,我们可以看到有一个图标指示该类是一个单例类还是一个组件。如果是一个组件,那么就会显示xtype属性。(一定要分清哪个是类,哪个是组件哦,不然以后使用起来就麻烦许多了)
在类名下面会根据具体类的情况显示如下菜单项:configs、properties、methods、events、super classes和sub classes。接着还有一个搜索框,可通过它来查询该类的特定属性、配置项、方法等等。
对于某些类的描述,api文档中会列出一些实例,并且某些实例提供了即时预览的功能,方便我们查看代码执行效果。
在页面的右边,会展现类的alternate names、hierarchy和mixns的信息。
当大家打开api文档时会发现有些方法被标记为deprecate,就是说这些方法已被弃用了。
在api文档的右上角我们可以看到一个搜索框,通过它可以在整份文档中搜索特定的类、方法、配置项、属性、事件、组合。
当然api文档还提供了官方的guides文档,让大家更容易入手ext。
ext js 4 sdk 目录如下:
一般我们涉及最多的是ext-all.js和ext.js这两个文件。
ext-all.js: 包含整套已压缩的ext js框架。使用时引入该文件到html文件,然后项目中只需包含该文件和resource文件夹即可。目录结构如下:
--extjs
--ext-all.js
--resources
ext.js: 只包含ext js已压缩的基础库。使用时引入该文件到html文件,然后项目中把src也包含进来。目录结构如下:
--ext.js
--src
我们还看到有*-dev.js和*-debug.js、*-debug-w-comments.js文件。下面我们逐一了解。
*-dev.js:内含无压缩代码和用于debug的代码,建议在开发和测试环境中使用;
*-debug.js:内含无压缩代码但不含用于debug的代码,建议在测试环境中使用;
*-debug-w-comments.js:内含无压缩代码但不含用于debug的代码,建议在测试环境中使用。
sdk的其他文件夹:
docs:含完整的api文档;
examples:含组件的使用实例;
overview:含新特性的快速浏览资料;
pkgs:含extjs的模块;
resources:含css和图片、主题等文件;
src:含extjs的完整源码;
welcome:含index.html所需的所有图片文件;
builds:含extjs的额外文件;
jsbuilder:含jsbuilder工具,用于项目构建。关于jsbuilder的详细资讯,请浏览http://www.sencha.com/products/jsbuilder(译者本人还没使用过这工具,请指教)
在builders文件夹中有下面几个文件:
ext-all-sandbox.js:沙盒模式的ext-all.js和ext-base.js;
ext-core.js:extjs的核心库;
ext-foundation.js:extjs的基础库。
最后要讲解的是bootstrap.js文件,它会根据具体的运行环境决定引用ext-all.js还是ext.js文件。除了下列情况外,bootstrap.js均会引用ext-all.js文件。
1.主机名(hostname)为localhost
2.主机名(hostname)为ip(v4)地址
3.协议名为file
extjs 4类系统中有如下激动人心的特性:
类定义和对象实例化方式;
组合;
自动化getter和setter;
动态加载类文件;
静态成员。
ext js4引入ext.define和ext.create方法来定义类和实例化。在本章我们将学习如何定义类和实例化对象。
1.3.1.1. 类定义
extjs 3我们需要继承object来定义类,代码如下:
myapp.newclass = ext.extend(object,{
// 类成员定义
});
而extjs 4我们可以如下的定义类:
ext.define("myapp.newclass",{
很明显,ext.extend已被ext.define代替了。
让我们对比一下extjs 3和extjs 4自定义window时的代码吧!
下面是extjs3的代码:
ext.namespace("myapp");
myapp.mywindow = ext.extend(ext.window,{
title: "welcome!",
initcomponent: function(){
ext.apply(this, {
items: [{
xtype: "textfield",
name: "tfname",
fieldlabel: "enter your name"
}]
});
myapp.mywindow.superclass.initcomponent.apply(this, arguments);
}
var win = new myapp.mywindow();
win.show();
可以看到我们必须使用ext.namespace来注册自定义的命名空间,否则抛出myapp未定义的异常信息。与此同时,若
ext.window没有完成加载,那么也会抛出ext.window未定义的异常信息。而extjs 4就省去了这个麻烦。下面是extjs
4的代码:
ext。define("myapp.mywindow", {
extend: "ext.window",
this.items = [{
xtype: "textfield",
name: "tfname",
fieldlabel: "enter your name"
}];
this.callparent(arguments);
var win = ext.create("myapp.mywindow");
extjs 4中以字符串的形式定义类和引用父类,所以并不存在该类未定义的说法。extjs
4的classmanager会检查ext.window是否已完成加载并已定义,若没有则推迟myapp.mywindow的实例化并自动完成
ext.window的加载。框架会为我们管理各类的加载顺序,并且ext.define会自动监测和创建省命名空间,省心多了。
另外我们可以看到,exjts
3中调用父类方法的语句为myapp.mywindow.superclass.initcomponent.apply(this,
arguments),而extjs 4就简约为this.callparent(arguments)。
对于override的方法使用this.callparent(arguments)就好比如c#的override方法中使用base.方法名(参数
1.......)。用于把子类的参数传递到父类的方法中。除了initcomponent外,常见的使用形式还有:
ext.define("parent",{
constructor: function(name){
this.name = name;
}
});
ext.define("child",{
extend: "parent",
constructor: function(name, sex){
this.sex = sex;
this.callparent([name]);// 参数为数组
var c = new child("john huang", "male");
或者 var c = ext.create("child", "john huang", "male"); // 建议使用该形式实例化对象
console.log(c.name);
console.log(c.sex);
建议使用ext.create实例化对象,这样可以利用extjs 4类系统的特性。
ext.define是ext.classmanager.create的别名,ext.create是ext.classmanager.instantiate的别名。
组合是extjs4的新特性,可用于实现多继承。该属性会以同步方式加载类文件,并实例化该类(译者推理其内部使用ext.create方法)。其他原文不翻译了,直接上实例吧!
基本用法:
ext.define("myclass.a", {
showa: function(){
console.log("a");
ext.define("myclass.b", {
showb: function(){
console.log("b");
ext.define("myclass.c", {
mixins: {
classa: "myclass.a",
classb: "myclass.b"
},
showc: function(){
console.log("c");
var objc = ext.create("myclass.c");
objc.showa(); // 控制台结果:a
objc.showb(); // 控制台结果:b
objc.showc(); // 控制台结果:c
方法同名时
情况1——多个mixins类拥有同名函数:
show: function(){
objc.show(); // 控制台结果:a
若
classb: "myclass.b",
classa: "myclass.a"
那么
objc.show(); // 控制台结果:b
结论:mixins中后者的方法无法覆盖前者的同名方法。
情况2——mixins类与当前类拥有同名函数:
classa: "myclass.a"
show: function(){
objc.show(); // 控制台结果:c
结论:方法的调用遵循最近优先原则,就是先查询直接类是否有该方法,有则调用,无则查询mixins中包含的类。
情况3——mixins类与父类拥有同名函数:
extend: "myclass.b"
结论:方法的调用遵循最近优先原则,优先级顺序从高到低——当前类、父类、mixins类。
当前类引用mixins类成员
alert: function(){
this.mixins.classa.show();
objc.alert(); // 控制台结果:a
先上代码吧!
基本使用方式:
config: {
name: "john huang",
sex: "male"
console.log(this.config.name);
var obja = ext.create("myclass.a");
obja.show(); // 控制台结果:john huang
obja.setname("john");
obja.show(); // 控制台结果:john
console.log(obja.getname()); // 控制台结果:john
console.log(obja.name); // 控制台结果:john
config属性会将为其属性自动添加setter和getter函数。
若打算修改setter的行为,可以重写“apply属性名”方法,该方法将为setter的内部实现。具体代码如下:
applyname: function(val){
this.name = "dev: " + val;
console.log(this.name);
var a = ext.create("myclass.a");
a.setname("john");
console.show(); // 控制台结果:dev: john
原文中说除了自动生成getter和setter,还会自动生成resetter。但经过实际操作我并没发现有此方法,那就需要我们自定义resetter了。在自定义前我们需要理解config属性、当前类、getter和setter的关系和原理。
下面我们通过实例来理解吧
1. console.log(a.config.name); // 控制台结果:john huang
2. console.log(a.name); // 控制台结果:undefined
3. console.log(a.getname()); // 控制台结果:dev: john
4. console.log(a.name); // 控制台结果:dev: john
5. console.log(a.config.name); // 控制台结果:john huang
语句3的结果是不是和我们预想的john
huang有所出入呢?不是说调用setname的时候才会调用applyname吗,为啥调用getname的时候也会调用applyname呢?其实
调用getname的时候不定会调用applyname方法,只有当语句2结果为undefined时才会有如此的效果,而且只有首次调用时会调用
applyname方法。如果在语句3前执行了a.name =
"john"或者a.setname("john"),那么就不调用applyname方法。
分析:
其实getname内部实现在首次调用和第n次调用时是不同的。
首次调用getname方法时的内部实现步骤如下:
1. 检查对象是否有name属性,有则执行步骤2,无则执行步骤3;
2. 返回name属性,并更新内部实现;
3. 以config.name为参数执行applyname函数,因为applyname函数体为this.name =
.....,就会添加name属性到对象中,然后更新内部实现。(若applyname函数体无this.name=...的语句,那么getname的
返回值将是undefined)
第n次调用getname方法是的内部实现如下:
function(){ return this[q]; },直接返回对象的属性。
结论: setter和getter是将config的成员属性复制(注意:为浅复制)为当前类的成员属性,然后对成员属性进行后续操作。
因此我们在重写applyname时需要遵守下列原则。
不要修改config的成员属性值
而在类内部成员函数中访问config的成员属性时建议如下操作:
},
showname: function(){
var name = this.name || this.config.name;
console.log(name);
updatename: function(val){
this.name = val;
现在大家应该对getter和setter、config、当前类的关系有所了解了。下面我们来自定义resetter吧!
name: "john huang"
/*
** @param configproperties{object/string/array} config的成员属性名
** @return {void}
*/
reset: function(configproperties){
if ("string" === typeof configproperties){
if (this.config.hasownproperty(configproperties)){
this[configproperties] = this.config[configproperties];
}
else if ("object" === typeof configproperties && null !== configproperties){
var properties = configproperties;
if ("[object object]" === object.prototype.tostring.call(configproperties)){
properties = object.getownpropertynames(configproperties);
for (var i = properties.length - 1; i >= 0; --i){
var property = properties[i];
if (this.config.hasownproperty(property)){
this[property] = this.config[property];
}
}
对象实例化时设置config成员值
在constructor方法中使用this.initconfig(参数对象),代码如下:
ext.define("a", {
config: {
name: "john huang",
sex: "male"
},
constructor: function(config){
this.initconfig(config);
var a = ext.create("a", {
name: "extjs",
sex: "i don't know"
}); 或 new a({
});
作为extjs 4的新特性,extjs框架为动态类加载提供一个整合依赖关系的管理系统。
但我们应该避免在产品中使用该特性,因为类文件的加载操作将严重影响用户体验。而在开发环境中使用该特性将有利于调试和项目文件结构的组织。
因发现原文中并未详细地描述动态类加载的相关内容,以下内容为结合原文及api文档总结而成,若有纰漏请大家多多指点。
动态加载分类:
同步加载:加载类文件时javascript线程将被阻塞直至类文件加载完成或当前类定义的操作被阻塞直至类文件加载完成。
涉及的类、方法和属性:
ext.create(加载类文件并实例化对象)
ext.loader.syncrequire(别名:ext.syncrequire) (加载类文件)
ext.class.requires(加载类文件)
ext.class.mixins(加载类文件并实例化对象)
ext.class.extend(加载类文件并实例化对象)
ext.data.field.type(加载类文件)
ext.data.association.associatedmodel(或ext.data.association.model) (加载类文件)
ext.data.store.model(加载类文件)
说明:上
述1、2的是调用该语句时就会发起xhq请求加载类文件,且javascript线程将被阻塞;3、4、5、6、7、8的是在类文件加载完成后解析代码时
发起xhq请求,只阻塞该类的定义操作,而不会阻塞javascript线程执行类定义以后的代码,若在实例化期间使用而事先未加载该类文件则会报异常
(ext.data.store.model就是可以在实例化store对象时设定其model值,若此时model指向的类文件没有加载那么就会抛出异
常)
。例子:
ext.define("test", {extend: "b"}); var test = new test(); 会报test未定义的异常。
异步加载:加载类文件时javascript线程可继续执行其他代码(包括类定义的操作),当类文件加载完成后可触发回调事件。
ext.loader.require(别名:ext.require)(加载类文件)
ext.class.uses(加载类文件)
说明:上述1的是调用该语句时就会发起xhq请求加载类文件;2的是在类文件加载完成后解析代码时发起xhq请求。
启动动态加载功能:
ext.loader.setconfig({ enabled:true }); api文档表示默认为false,但实践证明默认为true。
死锁问题:
动态加载类文件时,若多个类文件间彼此使用同步方式动态加载对方并形成类文件加载的闭环,便会产生死锁问题,并使浏览器无法正常工作。实例如下:
extend: "b"
ext.define("b", {
mixins: {
c: "c"
ext.define("c", {
requires: ["a"]
ext.syncrequire("a"); 或 ext.create("a"); // 发起类文件加载请求
说明:上述定义a、b、c三个类,并且分别使用extend、mixins、requires三种ext.class的属性来设置相互依赖关系从而形成类文件加载的闭环。
消除死锁:
1. 对于该类实例化时非前提条件的类文件,使用ext.class.uses属性异步加载;
2. 使用ext.require方法发起异步类文件加载请求。(不建议使用该方法,因为应在类的设计阶段就决定哪些依赖类需要用requires哪些可以用uses来加载)
可通过ext.class.statics属性来设置类的静态成员,具体使用如下:
statics: {
count: 0,
appname: "a"
constructor: function(){
++this.self.count; 或 ++this.statics().count;
getcount: function(){
return this.statics().count;
getappname: function(){
return this.self.appname;
var a = ext.create("a");
a.getcount(); // 结果:1
a.getappname(); // 结果:"a"
a.count; // 结果:1
a.appname; // 结果:"a"
说明:
类定义内部不能使用"this.statics.成员名"的方式访问静态成员,而要使用"this.self.静态成员名"或"this.statics().静态成员名";
类定义外部使用"类名.静态成员名"来访问类静态成员。
译者理解:this.self获取的就是类本定义本身,因此"this.self.静态成员名"实际与"类名.静态成员名"是一样的。而"this.statics().静态成员名"是另一种方法访问类静态成员。
extjs4在框架、核心库和组件上都进行了重构。通过上面的学习我想大家对新的类系统已经有了较全面的了解了。现在我们一同来学习extjs4的组件吧。当然有些变化并不兼容extjs3,因此下面的内容会介绍如何从extjs3迁移到extjs4。
在extjs4之前的版本中,若我们打算使用除extjs外如jquery等工具库时,我们需要引入由ext提供的适配器文件,如ext-jquery.adapter.js。
引入的文件如下:
ext-all.js
ext-jquery.adapter.js
jquery.js
ext适配器、第三方工具库关系图:
而在extjs4中就省心多了,无需适配器的支持直接就可以引用如jquery的工具库。
ext-all.js
jquery.js
关系图如下:
作用:在同一个页面中,同时使用extjs4和其他版本的extjs。
相关文件:
ext-all-sandbox.js
ext-all-sandbox-debug.js
ext-all-sandbox-dev.js
ext-sandbox.css
使用注意点:使用ext4代替ext关键字
引入的文件如下:
extjs3的文件
ext-sandbox.css
ext-all-sandbox.js
extjs一直提供基于自身的面向组件的类系统和架构,和相应配套的layout、state、utilities和data包。extjs 4的架构与extjs 3相似。
sencha诞生于2010年,与此同时还推出了extjs的兄弟产品sencha touch。sencha
touch是移动设备的javascript框架,其架构不同于extjs3。到了exjts4
release版时,sencha决定融合extjs4和touch的架构,而sencha平台就因此而诞生了。平台中提供部分通用代码如data、
layouts、大部分utility的方法和新的charting和animation包。通过这样,sencha的团队就能持续提供稳定可用容易维护
的产品代码了。当然这样就降低作为使用者的我们学习touch的曲线了。(要知道extjs的因功能强大,学习曲线可陡着呢)
该包包括负责数据加载和保存的类。现在让我们了解一下它吧。
store(数据仓库):过去我们需要事先确认加载的数据是json还是xml格式从而选择使用jsonstore还是xmlstore,现在
extjs4的最新store类会自动监测加载的数据格式,并且store还提供了排序、过滤的功能,通过最新的reader类还能从服务端读取格式化数
据。
model(数据模型):model是extjs独有的类,类似于extjs旧有版本的record,但又提供了如关联关系(associations)和数据验证(validations)的功能。
proxy(数据代理):proxy类负责加载和保存数据,和接收reader和writer类的实例对象。我们可以将某类型的proxy附加到
store或model类中(不像extjs旧有版本那样proxy必须附加到store中)。extjs4还新增了localstorageproxy
和sessionstorageproxy,提供将数据保存到html5 local storage和session storage的功能。
提醒:上述的内容不是100%兼容extjs旧有版本的代码。
extjs4引入全新的draw包,提供基于html5标准的自定义画图功能。我们可以画如方形、圆形或者是文本等基本形状。同时它也提供了通过svg path画复杂形状的功能。draw包是chart包的基础。
extjs3引入全新的chart组件,但其依赖于flash。而extjs4的chart组件不再依赖flash了,而是纯javascript驱动
基于svg(scalable vector graphics)、canvas和vml(vector markup language)。
通过extjs4我们可以画任何想要的图表。基本的图表有bar/column、line/area、scatter、radar,我们可以通过这些基本的图表来组合出各种自定义的图表。
布局是extjs中最重要和强大的特性之一。ext2中的布局渲染速度快但不够灵活,ext3中灵活性上进行了修改但牺牲了新能。而ext4中重写了布
局引擎,现在不仅更灵活了而且渲染速度也更快了。此外还新增了如docklayout、toolbarlayout和fieldlayout等布局。
表格是我们用得最多的一个extjs组件。extjs4对其进行了重写,使其更快、更容易自定义并拥有更高的性能。
在extjs3使用表格一次展现上千条数据时会出现各种性能问题,解决方法是使用一个插件来是表格支持缓存。而extjs4的表格就内置缓存机制,现在不用再担心该问题了。
表格的编辑功能在extjs4中也得到了改进。在extj3中如果我们想使用表格来编辑信息,那么就要用一个特殊的表格——editorgrid,或者
是使用第三方插件roweditor。在extjs4中,内置了roweditor插件,我们只需将该插件附加到表格(grid)中即可编辑表格数据信
息。(译者语:将第三方官方化是使产品更稳定的做法)
在extjs3中若我们想为表格添加新功能,我们必须继承表格后自定义表格类或通过自定义插件的形式来实现。extjs4引入了
ext.grid.feature,其提供了基本的特性让我们自定义新的表格特性,而不必修改表格的核心部分,从而是表格更稳定。(译者语:本人还没搞懂
该方式和plugin的区别,只是大概明白这样做的理由是把可扩展的部分独立出来,免除核心部分被修改而表格功能又能最大化的灵活修改)
extjs旧有版本中会完整地创建表格的html标签,不管实际上是否使用了其某功能(编辑、行扩展),这使得产生了不少无用html标签也降低了性能
(译者语:曾试过在ie6个上一次加载8000个html标签,足足加载了2分钟啊)。extjs4遵循节约原则,开启的功能才会为其创建html标签,
因此我们再也找不到extjs3中的listview组件了(listview是grid的轻量级组件,只用于数据展现)。
表单是另一个我们经常使用到的组件,而extjs4为其增添了很多新特性。首先是不再限制表单只能用formlayout作为其布局,而是可以使用任何extjs提供的布局方式。
另外extjs4还提供了fieldcontainer类,用于把其他组件(如表格等)打包到到表单中。
关于数据合法性验证方面也作出了重大的修整。
通过javascript生产访问性良好的应用是一件十分困难的事情。而extjs4引入了下列三种特性来帮助我们提供应用的可访问性。
1. 每个组件均有特性来支持aria(accessible rich internet application);
2. 支持键盘导航;
3. 提供全新的主题来提供访问性。
大家都知道修改extjs旧有版本的主题是一件多么痛苦的事情,而extjs4通过使用sass和compass这两种优秀的工具使得自定义主题变得一件写意的事情。
在这一章我们对extjs4新的类系统有了相当程度的理解,对extjs4相对于旧有版本的修整也有了大概的了解。我想大家应该和我一样对这些新特性感到兴奋,当然脑海中对extjs4也产生了很多的问号。那下一章我们将一起继续extjs4的旅途^_^!
转载请标明出处哦!http://www.cnblogs.com/fsjohnhuang/archive/2013/01/29/2880705.html