Extjs4新特性
Extjs 4相对于之前的版本作出了重大的修正。其中包括全新的类系统、新平台的引入、API的修整和加强还有新组件的引入(如新的图表和图形组件)。Extjs 4提供更快速、更稳定的用户体验,并且让开发人员更容易上手。 1.1. 入手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进行了命名习惯的改进,同时使得部分的配置参数更易于使用。 1.1.1. 包和命名空间的改进 对于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的全新类名。 1.1.2. API文档的使用(日后经常和它打交道) 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。 1.2. Extjs新平台的架构 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也包含进来。目录结构如下: --extjs --ext.js --src --resources 我们还看到有*-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 1.3. Extjs 4的类系统 Extjs 4类系统中有如下激动人心的特性: 类定义和对象实例化方式; 组合; 自动化getter和setter; 动态加载类文件; 静态成员。 1.3.1. 类定义与对象实例化 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代替了。 1.3.2 继承 让我们对比一下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", title: "Welcome!", initComponent: function(){ this.items = [{ xtype: "textfield", name: "tfName", fieldLabel: "Enter your name" }]; this.callParent(arguments); } }); var win = Ext.create("MyApp.MyWindow"); win.show(); 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的别名。 1.3.3 组合属性(mixins) 组合是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类拥有同名函数: Ext.define("MyClass.A", { show: function(){ console.log("A"); } }); Ext.define("MyClass.B", { show: function(){ console.log("B"); } }); Ext.define("MyClass.C", { mixins: { classA: "MyClass.A", classB: "MyClass.B" } }); var objC = Ext.create("MyClass.C"); objC.show(); // 控制台结果:A 若 Ext.define("MyClass.C", { mixins: { classB: "MyClass.B", classA: "MyClass.A" } }); 那么 objC.show(); // 控制台结果:B 结论:mixins中后者的方法无法覆盖前者的同名方法。 情况2——mixins类与当前类拥有同名函数: Ext.define("MyClass.A", { show: function(){ console.log("A"); } }); Ext.define("MyClass.C", { mixins: { classA: "MyClass.A" }, show: function(){ console.log("C"); } }); var objC = Ext.create("MyClass.C"); objC.show(); // 控制台结果:C 结论:方法的调用遵循最近优先原则,就是先查询直接类是否有该方法,有则调用,无则查询mixins中包含的类。 情况3——mixins类与父类拥有同名函数: Ext.define("MyClass.A", { show: function(){ console.log("A"); } }); Ext.define("MyClass.B", { show: function(){ console.log("B"); } }); Ext.define("MyClass.C", { extend: "MyClass.B" mixins: { classA: "MyClass.A" } }); var objC = Ext.create("MyClass.C"); objC.show(); // 控制台结果:B 结论:方法的调用遵循最近优先原则,优先级顺序从高到低——当前类、父类、mixins类。 当前类引用mixins类成员 Ext.define("MyClass.A", { show: function(){ console.log("A"); } }); Ext.define("MyClass.C", { mixins: { classA: "MyClass.A" }, alert: function(){ this.mixins.classA.show(); } }); var objC = Ext.create("MyClass.C"); objC.alert(); // 控制台结果:A 1.3.4. 配置项属性(config,自动创建setters和getters) 先上代码吧! 基本使用方式: Ext.define("MyClass.A", { config: { name: "John Huang", sex: "male" }, show: function(){ 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的内部实现。具体代码如下: Ext.define("MyClass.A", { config: { name: "John Huang", sex: "male" }, applyName: function(val){ this.name = "dev: " + val; }, show: function(){ console.log(this.name); } }); var a = Ext.create("MyClass.A"); a.setName("John"); console.show(); // 控制台结果:dev: John 原文中说除了自动生成getter和setter,还会自动生成resetter。但经过实际操作我并没发现有此方法,那就需要我们自定义resetter了。在自定义前我们需要理解config属性、当前类、getter和setter的关系和原理。 下面我们通过实例来理解吧 Ext.define("MyClass.A", { config: { name: "John Huang", sex: "male" }, applyName: function(val){ this.name = "dev: " + val; } }); var a = Ext.create("MyClass.A"); 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的成员属性时建议如下操作: Ext.define("MyClass.A", {
config: {
name: "John Huang",
sex: "male"
},
}); 现在大家应该对getter和setter、config、当前类的关系有所了解了。下面我们来自定义resetter吧! Ext.define("MyClass.A", { config: {
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({ name: "Extjs", sex: "I don't know" }); 1.3.5. 动态类加载 作为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请求。
- 涉及的类、方法和属性:
- 涉及的类、方法和属性:
而在Extjs4中就省心多了,无需适配器的支持直接就可以引用如JQuery的工具库。 引入的文件如下: ext-all.js jquery.js 关系图如下:
1.4.2. 沙盒模式 作用:在同一个页面中,同时使用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 1.5. Sencha平台 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的因功能强大,学习曲线可陡着呢)
1.5.1. Data包 该包包括负责数据加载和保存的类。现在让我们了解一下它吧。 - 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的功能。
转载于:https://www.cnblogs.com/niejunchan/p/4998304.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
