Extjs-4.2.1(二)——使用Ext.define自定义类
鸣谢:http://www.cnblogs.com/youring2/archive/2013/08/22/3274135.html
--------------------------------------------------------------------------
本篇博客主要介绍了Etxjs如何自定义类的,以及Extjs的继承、属性的封装,这类似于java语言的继承、封装的特点。此外,在java语言中,分层是重要的思想,如类的定义与创建其实例并调用方法一般都是分别写在不同的java文件中,javascript语言由于没有类的概念,因此总是所有的代码写在一个js文件中,而Extjs则不同,它与java语言一样具有面向对象的特性,在本博客中所介绍的Extjs的动态加载描述了Extjs是如何将类的定义与创建类的实例及调用方法进行分层的。
一、什么是define?
define是Extjs的一个方法,用于定义一个类或覆盖。详情见API:http://extjs-doc-cn.github.io/ext4api/#!/api/Ext
二、ExtJS 中自定义类
在ExtJS中,定义一个Person类:
Ext.onReady(function(){ Ext.define('Person',{ name:'wang', say:function(){ alert('hi,'+this.name); } }) var obj = new Person(); obj.say(); })
在这段代码中,我们使用了Ext.define方法自定义一个Person类,它具有Name,具有Say 方法,运行结果如下:
在上面的类中,name属性被赋了一个指定的值,显然,除了静态属性,在类中的属性仅需被声明,在创建实例时进行赋值,这就需要构造函数了。看下面的代码:
Ext.onReady(function(){ Ext.define("Person2", { //定义、初始化成员属性 Name: '', Age: 0, //定义成员方法 Say: function (msg) { Ext.Msg.alert(this.Name + " Says:", msg); }, //定义构造函数 constructor: function (name, age) { this.Name = name; this.Age = age; } }); var Tom = new Person2("Tom", 26); Tom.Say("Hello"); })
运行结果:
三、ExtJS 中类的继承
ExtJS 允许对现有的类进行扩展,其扩展可以通过继承来实现。接下来我们就对刚刚使用ExtJS定义的Person2类进行继承,定义一个Developer类,它继承自Person2,同时还拥有Coding方法,代码如下:
/** * 此js演示了Etxjs类的继承 */ Ext.onReady(function(){ //基类 Ext.define("Developer", { extend: 'Person2',//继承 Coding: function (code) { Ext.Msg.alert(this.Name + " 正在编码..", code); }, constructor: function(){ this.callParent(arguments); } }); var Bill = new Developer("Bill", 26); Bill.Coding("int num1 = 0; "); })
从代码中可看出,ExtJS 使用 extend来实现继承。我们为Developer 类添加了Coding 方法,这是我们对Person类进行的扩展。在构造函数中,通过调用this.callParent 方法,实现对属性的初始化。需要说明的是,如果此处只调用了父类的构造方法,则可以省略掉,ExtJS 会自动为我们调用父类的构造函数。所以我们此处的代码可以进行简化:
/** * 此js演示了Etxjs类的继承 */ Ext.onReady(function(){ //基类 Ext.define("Developer", { extend: 'Person2',//继承 Coding: function (code) { Ext.Msg.alert(this.Name + " 正在编码..", code); } }); //基类在new实例时如果在其类中没有定义构造方法,则调用其父类的构造方法。 var Bill = new Developer("Bill", 26); Bill.Coding("int num1 = 0; "); })
需要注意的是:1.如果你在子类中使用了构造函数,ExtJS 则不会再自动调用父类的构造函数;2.像java导包一样,在html中要导入父类的js文件,代码如下:
<!-- 导入父类 --> <script type="text/javascript" src="../js/define/define2.js"></script> <script type="text/javascript" src="../js/define/define3.js"></script>
运行结果:
四、ExtJS 中类的选项 - config
首先看一个例子,我们在ExtJS中定义一个Window对象,代码如下:
var win = Ext.create("Ext.window.Window", { title: '示例窗口, width: 300, height: 200 }); win.show();
在上面的代码中,我们通过Ext.create方法创建了一个Window 对象,Ext.create 方法的第一个参数是类名,第二个参数是类的选项,它是一个JSON格式的对象,用来初始化Window对象。我们的窗口运行如下:
试想一下,如果我们的类中有几十个属性,那么我们使用构造函数就要传入几十个参数来对它完成初始化,这是一件很恐怖的事情。还好ExtJS 为我们提供了这种便利,我们可以在定义类的时候为它添加配置项——config,它是Extjs的属性包装器,为属性提供get和set方法。
我们来修改Person类,使它可以通过config初始化:
/** * define-config * 此js演示了在定义的类中将类的成员属性放在config中并且如何实例化对象的。 */ Ext.onReady(function(){ Ext.define("Person", { config: { Name: '', Age: 0 }, Say: function (msg) { Ext.Msg.alert(this.Name + " Says:", msg); }, Say2: function (msg) {//在方法中,“this.config.属性名”和“this.属性名”的形式都可以调用成员属性。 Ext.Msg.alert(this.config.Name+","+this.Age + " Says:", msg); }, constructor: function (config) { this.initConfig(config); } }); //注意:因为在Person类中将成员属性放进了config中,因此已不能用new的方式进行实例化了。 var Jack = new Person('Jack',28); // Jack.Say('hi'); // alert(Jack.getAge()); //使用Ext的create方法创建并返回一个实例 var Tom = Ext.create("Person", { Name: 'Tom', Age: 26 }); Tom.Say("Hello"); // alert(Tom.getAge());//26 注:“Tom.config.Age”、“Tom.Age”都可以得到Age的值 //使用Ext自动生成的set、get方法设置、访问实例属性 Tom.setAge(18);//注:“Tom.Age=18”也可以——这是js赋值的方法 // alert(Tom.getAge());//18 注:“Tom.Age”也可以——这是js取值的方法 })
我们在类的定义中添加了config项,将需要在配置中完成的属性添加在里面,而在构造函数中,我们通过调用this.initConfig方法完成对config的初始化;在定义Person类对象的时候,使用Ext.create方法,传入类名Person以及配置项,运行结果:
五、ExtJS 中类的别名 - alias
在我们查看ExtJS API 的时候,在左侧常会有这样的说明:
红色方框圈出的部分是这个类的别名,它对应类的全称是 Ext.window.Window,由此可以看出别名更加简单,容易记忆和书写。我们在实例化类的时候,可以使用别名来替代类名全称,例如我们之前定义的win对象,他的代码可以修改为:
/** * define-alias * 此js演示了利用"alias"给定义的类起别名。 */ Ext.onReady(function(){ Ext.define("vo.Person", { config: { Name: '', Age: 0 }, alias:"Person",//给定义的类起个别名 Say: function (msg) { Ext.Msg.alert(this.Name + " Says:", msg); }, Say2: function (msg) {//在方法中,“this.config.属性名”和“this.属性名”的形式都可以调用成员属性。 Ext.Msg.alert(this.config.Name+","+this.Age + " Says:", msg); }, constructor: function (config) { this.initConfig(config); } }); //使用Ext的create方法创建并返回一个实例 var Tom = Ext.create("Person", { Name: 'Tom', Age: 26 }); Tom.Say("Hello"); })
六、ExtJS 中的动态加载
在Ext.create 方法的介绍中,有这样一段描述:
它的意思是:如果Ext.loader 可用,且类还没有被定义,它将试图通过同步加载来加载类。
接下来我们来试试类动态加载的功能。我们的类vo.Person 类的位置是:
下面是Person.js的代码:
/** * define * 此js定义一个Person类 */ Ext.define("vo.Person", { config: { Name: '', Age: 0 }, alias:"Person",//给定义的类起个别名 Say: function (msg) { Ext.Msg.alert(this.Name + " Says:", msg); }, Say2: function (msg) {//在方法中,“this.config.属性名”和“this.属性名”的形式都可以调用成员属性。 Ext.Msg.alert(this.config.Name+","+this.Age + " Says:", msg); }, constructor: function (config) { this.initConfig(config); } });
下面是在HTML中需要引用的js(define6.js)代码:
/** * define-alias * 此js演示了Ext的动态加载 */ //js获取项目根路径,如:http://localhost:8081/extjsTest1 function getRootPath(){ //获取当前网址,如: http://localhost:8081/extjsTest1/define/define6.jsp var curWwwPath=window.document.location.href; //获取主机地址之后的目录,如: extjsTest1/define/define6.jsp var pathName=window.document.location.pathname; var pos=curWwwPath.indexOf(pathName); //获取主机地址,如: http://localhost:8081 var localhostPaht=curWwwPath.substring(0,pos); //获取带"/"的项目名,如:/extjsTest1 var projectName=pathName.substring(0,pathName.substr(1).indexOf('/')+1); return(localhostPaht+projectName); } Ext.onReady(function(){ Ext.Loader.setConfig({ enabled:true, paths:{ vo: getRootPath()+"/js/vo"//告诉Extjs命名空间“vo”的路径 } }) /** * 在Extjs创建vo.Person的实例Tom时发现该类没有被定义,因此它会加载命名空间vo指定路径下的Person.js, * 这就是Extjs的动态加载。 */ var Tom = Ext.create("vo.Person", {//注意:使用动态加载,应使用类的全名,如果使用别名Extjs无法找到正确的路径。 Name: 'Tom', Age: 26 }); Tom.Say("Hello"); })
在完成Loader 的配置以后,我们就可以移除掉对Person.js的引用了,下面是HTML引用文件:
<link rel="stylesheet" type="text/css" href="../ext-4.2.1/resources/ext-theme-neptune/ext-theme-neptune-all.css"> <script type="text/javascript" src="../ext-4.2.1/ext-all.js"></script> <script type="text/javascript" src="../ext-4.2.1/locale/ext-lang-zh_CN.js"></script> <script type="text/javascript" src="../js/define/define6.js"></script>
可以看到,上面并没有引用项目中的"../js/Vo/Person.js"这个js文件,运行结果:
另外,我们还可以手动的加载Person.js,代码如下:
/** * define-alias * 此js演示了Ext的动态加载 */ //js获取项目根路径 function getRootPath(){ var curWwwPath=window.document.location.href; var pathName=window.document.location.pathname; var pos=curWwwPath.indexOf(pathName); var localhostPaht=curWwwPath.substring(0,pos); var projectName=pathName.substring(0,pathName.substr(1).indexOf('/')+1); return(localhostPaht+projectName); } Ext.onReady(function(){ Ext.Loader.setConfig({ enabled:true, paths:{ vo: getRootPath()+"/js/vo"//告诉Extjs命名空间“vo”的路径 } }) //加载Person.js Ext.require("vo.Person"); var Tom = Ext.create("Person", {//fail:使用Ext.require方法加载Person.js无法用vo.Person的别名Person创建实例 Name: 'Tom', Age: 26 }); Tom.Say("Hello"); })
但可惜的是,目前得到的是失败的结果,运行,在谷歌浏览器出现以下错误:
说明Ext.require没有正确加载Person.js
小结:Extjs的动态加载不仅实现了分层设计的思想,而且对于提高系统性能有重要的意义——这类似于hibernate的延迟加载的机理——动态代理。