一直感觉Ext在前台方面效果做的比较酷,最近想抽时间学习一下,应用到自己的项目中;下面是在学习各种Ext相关文档、博客以及论坛过程中汇总的一些知识点以及解惑。 (如有侵权请留言)
概念:
(1)ExtJS是一个面向开发RIA也即富客户端 的AJAX应用,是一个用javascript写的,主要用于创建前端用户界面,是一个与后台技术无关的前端ajax框架。(以前是基于YAHOO-UI ,现在已经完全独立了)
(2)之所以说是框架,因为它能够帮助我们在页面上快速而简单构建各种各样的控件,简化我们自己去写庞大js实现;它是一种纯面向对象的JS框架。扩展性相当的好,可以自己写扩展,自己定义命名空间,web应用可能感觉太大,不过您可以根据需要按需动态的加载您想要的类库就可以了,避免了网络传输流量问题。
(3)它提供了丰富的,非常漂亮的外观体验,成为众多界面层开发人员的追捧,更重要的是它核心的组件基本覆盖了我们构建富客户端 的常用的组件以及各种功能,在统计方面做的也非常出色。
(4)在3.0的时候提供了类似与dwr的方式调用后台代码,交互更加简单;4.0版本又提出了MVC模式的开发,支持组件化、模块插拔化设计以及提供本地数据源的支持。
第一章 EXTJS的基本概念
1. 组件component : 能够以图形化形式呈现界面的类,其中还可以分为容器组件与元件组件。
2. 类
提供功能的非图形可形的类,它们为图形类提供了有力的支持
按其功能可分为:数据支持类(Data)、拖放支持类(DD)、布局支持类(layout)、本地状态存储支持类(state)、实用工具类(Util)。
密封类:不能被扩展的类
原型类:扩展了javascript标准类库中的类
3. 方法
作为类的功能体现,能够产生改变对象本身产生变化的直接因素
方法按访问形式可分为公有方法与私有方法。但由于javascript从原理上根本不支持这种结构,因此在EXTJS中,私有与公有方法完全凭借着用户自觉,没有像JAVA那样的强制性。
4. 事件
由类定义的,并且可以在类对象自身状态发生改变的触发。
只有被定阅的事件才会有效
如果不需要此事件,应该进行退定,增强程序的执行效率。
5. 配置选项
用以初始化一个EXTJS类对象的手段
注意,配置选项并不一定就是属性,总算是属性,也有可能出现属性返回的类型与你当初指定的配置选项类型不一致的情况。
6. 属性
能够在程序运行期间,能够被访问,用以了解当前类对象的状态。
在实际的编程中,EXTJS的属性设置,比较差劲,需要通过了解其源代码,才能了解各种实用属性的用处。
7. 命名空间
能够将编写好的EXTJS类进行有效组织的手段。
这个也是EXTJS能够称之为优秀AJAX框架的特征之一。
第二章 Ext4.0新特性以及常用数据处理功能
1. extjs4.0对原生javaScript功能进行了扩展(API中的Utilities模块中的NativeExtensions)
Utilities:常用的一些工具处理类
Native Extensions
Ext.Array
Ext.Number
Ext.Object
Ext.String
Ext.JSON
Ext.Date
Ext.Function
具体扩展了那些,请参照具体的API说明,扩展的原理eg:
var Person = {name:'yfc',age:26}; //alert(Person['name']); //extjs4.0提供getKey的函数 //alert(Ext.Object.getKey(Person,'yfc')); Object.prototype.getValue = function(key,defValue){ if(this[key]){ return this[key]; }else{ return defValue; } } alert(Person.getValue("email","[email protected]")); //由于给Object的原型加上了一个getValue的函数,这样所有的对象(都继承Object)默认都会拥有这个函数。
2. 事件机制与新特性
(1)给对象加事件:
Ext.get("元素ID").on("click",function(){ //函数处理部分 });
(2)新特性:create与define(extend 、requires、config、mixins、alias以及statics )。
//create第一个参数为类路径,第二个参数为该类的一些初始化参数值(以对象的形式传递) var win = Ext.create('Ext.window.Window',{ width:400, height:300, title:'uspcat' }); win.show();
var o = { say : function(){ alert(11111); } } //通过o.say()调用函数 var fn = Ext.Function.alias(o,'say'); fn();//通过别名的方式我们就可以直接调用fn()等于o.say()。
//create第一个参数是类的全路径,第二个参数则是类的内容 Ext.define('Bmsys.ml.Window', { extend:'Ext.window.Window', title: 'Window', closeAction: 'hide', width: 380, height: 300, resizable: false, modal: true, //定义一些自己的扩展参数 myTitile: 'myWindow', setTitle: function(){ this.title = this.myTitle; } //初始化的方法(类似java中的构造方法) initComponent: function(){ this.setTitle(); this.callParent(arguments); } }); var win = Ext.create('Bmsys.ml.Window',{ titile: 'youWindow'; } ); win.show();//此时创建出来窗体的标题是myWindow,说明创建时,传入的初始化参数比构造器先执行。
注意:属性只能在define时定义,不能通过win.myHeight = function(){...}添加属性。
//这时候要启用自动加载 Ext.Loader.setConfig({ enabled:true, paths:{ myApp:'js/Bmsys/ml' //js文件相对路径,需要与命名空间保持一致 } }); //这时候只要保证Window.js放在js/Bmsys/ml这个目录下命名空间为Bmsys.ml.Window就可以了。 //这时就不需要在JSP文件中引入Window.js,等到下面的程序被执行时,才会根据命名空间去到后台加载Window.js。 //原理就是通过命名空间与文件路径,拼接好后通过写入<script>标签的方式加载。 var win = Ext.create('Bmsys.ml.Window',{ titile: 'youWindow', requires: ['Bmsys.ml.Window'] } ).show();
Ext.define('Bmsys.ml.Window', { extend:'Ext.window.Window', title: 'Window', width: 380, height: 300, //定义一些自己的扩展参数 myTitile: 'myWindow', config: { myHeight : 800 } }); var win = Ext.create('Bmsys.ml.Window',{}); alert(win.getMyTitle());//报错,没有定义getMyTitle函数 alert(win.getMyHeight());//正常弹出值为800 //放在config里面定义的属性,Ext会自动给这个属性加上get、set方法。
Ext.define("say",{ cansay:function(){ alert("hello"); } }) Ext.define("sing",{ sing:function(){ alert("sing hello 123"); } }) //通过类的混合,就可以轻松拥有上面两个类里面的函数。 Ext.define('user',{ mixins :{ say : 'say', sing: 'sing' } }); var u = Ext.create("user",{}); u.cansay();//say类里面的方法 u.sing();//sing类里面的方法
Ext.define('Computer', { statics: { factory: function(brand) { // 'this' in static methods refer to the class itself return new this(brand); } }, constructor: function() { ... } }); //直接通过类名'.'的方式访问静态方法 var dellComputer = Computer.factory('Dell');
//我们利用Ext.define来创建我们的模型类 //DB table person(name,age,email) Ext.define("person",{ extend:"Ext.data.Model", fields:[ {name:'name',type:'auto'}, {name:'age',type:'int'}, {name:'email',type:'auto'} ] }); //定义的时候,不需要每次写extend:"Ext.data.Model" Ext.regModel("user",{ fields:[ {name:'name',type:'auto'}, {name:'age',type:'int'}, {name:'email',type:'auto'} ] }); //实例化我们的person类 //1.new关键字 var p = new person({ name:'uspcat.com', age:26, email:'[email protected]' }); //alert(p.get('name')); var p1 = Ext.create("person",{ name:'uspcat.com', age:26, email:'[email protected]' }); //alert(p1.get('age')); var p2 = Ext.ModelMgr.create({ name:'uspcat.com', age:26, email:'[email protected]' },'person'); alert(p2.get('email')); //实例不能直接通过getName得到类名,因为这个方法是类的 class object.getClass.getName //alert(p2.getName()); //通过类.getName可以获得类名,因为person是模型类的定义,而不是实例 alert(person.getName());
//在校验之前,修改原始类里属性的默认值 Ext.data.validations.lengthMessage = "错误的长度"; Ext.onReady(function(){ //通过apply方法来在原始的校验器类上扩展我们自定义验证机制的的一个新的验证方法 Ext.apply(Ext.data.validations,{ //自定义的校验类型函数 age:function(config, value){ var min = config.min; var max = config.max; if(min <= value && value<=max){ return true; }else{ this.ageMessage = this.ageMessage+"他的范围应该是["+min+"~"+max+"]"; return false; } }, ageMessage:'age数据出现的了错误' }); //定义一个带有校验的模型类 Ext.define("person",{ extend:"Ext.data.Model", fields:[ {name:'name',type:'auto'}, {name:'age',type:'int'}, {name:'email',type:'auto'} ], validations:[ //type的值就是Ext.data.validations里方法名称 //field是你要校验字段名 //field后面的参数就是名称等于type值的函数的参数。 {type:"length",field:"name",min:2,max:6}, {type:'age',field:"age",min:0,max:150} ] }); var p1 = Ext.create("person",{ name:'uspcat.com', age:-26, email:'[email protected]' }); //通过validate()可以得到数据校验的错误集合 //每个error里面含有两个属性(field---校验字段的名,message---校验函数返回的错误信息) var errors = p1.validate(); var errorInfo = []; errors.each(function(v){ errorInfo.push(v.field+" "+v.message); }); alert(errorInfo.join("\n")); });
Ext.define("person",{ extend:"Ext.data.Model", fields:[ {name:'name',type:'auto'}, {name:'age',type:'int'}, {name:'email',type:'auto'} ], //通过代理从后台获取数据(数据要与model的fields里面的字段相对应) proxy:{ type:'ajax', url:'person.jsp' } }); var p = Ext.ModelManager.getModel("person"); //通过load方法来触发proxy加载数据 p.load(1, { scope: this, //record.data就是加载进来的一个数据实例对象 success: function(record, operation) { alert(record.data.name) } });
//类老师 Ext.regModel("teacher",{ fideld:[ {name:'teacherId',type:"int"}, {name:'name',type:"auto"} ], //建立老师与学生的1对多关系 hasMany:{ //所关联的模型 model: 'student', name : 'getStudent', //关系字段 filterProperty: 'teacher_Id' } }); //学生 Ext.regModel("student",{ fideld:[ {name:'studentId',type:"int"}, {name:'name',type:"auto"}, {name:"teacher_Id",type:'int'} ] }); //假设t是老师的一个实例,就可以通过t.students 得到子类student的一个store数据集合
var userData = { //读写器默认读取的记录总数的属性 //total : 200, //采用我们自定义的变量来标识总条数,这时后需要在读写器中配置total所对应我们自定义的变量 count:250, user:[{auditor:'yunfengcheng',info:{ userID:'1', name:'uspcat.com', orders:[ {id:'001',name:'pen'}, {id:'002',name:'book'} ] }}] }; //model Ext.regModel("user",{ fields:[ {name:'userID',type:'string'}, {name:'name',type:'string'} ], //配置一对多的关系 hasMany: {model: 'order'} }); Ext.regModel("order",{ fields:[ {name:'id',type:'string'}, {name:'name',type:'string'} ], //配置多对一的关系 belongsTo: {type: 'belongsTo', model: 'user'} }); var mproxy = Ext.create("Ext.data.proxy.Memory",{ model:'user', data:userData, //读写时的参数配置 reader:{ type:'json',//读取的类型(json/xml/array) root:'user',//指定读取开始的根节点 implicitIncludes:true,//是否级联读取关联的子节点(一对多的关系中体现) totalProperty:'count',//配置我们返回的总条数变量名称 record : 'info'//服务器返回的数据可能很复杂,用record可以筛选出有用的数据信息,装在带Model中,其它的参数忽略。 } }); //用内存代理来读取数据,其它的方式一样 mproxy.read(new Ext.data.Operation(),function(result){ var datas = result.resultSet.records; alert(result.resultSet.total); Ext.Array.each(datas,function(model){ alert(model.get('name')); }); var user = result.resultSet.records[0]; var orders = user.orders(); orders.each(function(order){ alert(order.get('name')) }); })
Ext.regModel("person",{ fields:[ 'name','age' ], proxy :{//在proxy下,你可以配置reader(读),同样也可以配置writer(写) type:'ajax', url:'person.jsp', writer:{//配置一些写的参数 //type:'json' type:'xml' //把js对象以xml的方式,传入后台 } } }); Ext.ModelMgr.create({ name:'uspcat.con', age:1 },'person').save();
Ext.define("person",{ extend:'Ext.data.Model', fields:[ {name:'name'}, {name:'age'} ], proxy:{ type:'memory' } }) var s = new Ext.data.Store({ //model:'person', data:[ {name:'uspcat.com',age:1}, {name:'yfc',age:26} ], //有了fields,我们就不需要在单独定义Model并且引用 fields:[ {name:'name'}, {name:'age'} ], //通过data属性,请偶们已经能够把数据初始化好了 //proxy是动态的区后台去数据 //proxy:{ // type:'ajax', // url:'person.jsp' //} //autoLoad:true }); s.load(function(records, operation, success){ //遍历 Ext.Array.each(records,function(model){ alert(model.get('name')); }); //过滤出字段name='yfc' s.filter('name',"yfc"); s.each(function(model){ alert(model.get('name')); }); //通过正则来查找数据集里面的记录,返回该记录的索引 var index = s.find('name','yfc',0,false,true,false); alert(s.getAt(index));//当前的Model对象 });
//json格式的数据 var jsondata = "{id:'01',name:'uspcat.com','age':26,email:'[email protected]'}"; //xml格式的数据 var xmldata = "<user><name>mlmlml</name><age>19</age></user>"; //构建Ext的Ajax请求 Ext.Ajax.request({ url : 'person.jsp', method : 'POST', timeout :3000, //请求的参数值 params:{id:'01'}, //可以提交form表单,只需要写表单的ID form:"myform", //下面是两种不同格式的请求参数 jsonData:jsondata, xmlData:xmldata, //一些操作的函数,第一个为响应的值,第二个参数是请求的参数值 success :function(response , options){ alert(eval(response.responseText)[0].name); }, failure :function(response , options){ alert(response.responseText+" "+options) } });
//get通过dom元素的id方式获得的是元素的对象 //getCmp通过定义对象ID的方式获得的是定义的对象,而不是简简单单的元素了 //getDom通过dom元素的id方式获得的是dom元素 var time = Ext.get("time").getLoader(); //ajax常用的局部改变元素的值 time.load({ url:'/extjs/extjs!getTime.action', renderer:function(loader,response,request){ var time = response.responseText; Ext.getDom("time").value = time; } }); //给元素设置定时的axja请求方式 i.startAutoRefresh(1000,{ url:'/extjs/extjs!getI.action', renderer:function(loader,response,request){ var i = response.responseText; Ext.getDom("i").value = i; } });
//这个是直接到页面中获得元素的对象 var div01 = Ext.core.Element.fly("div01"); //鼠标滑过的时候增加一个样式滑出的时候移除样式,值是样式的名称 div01.addClsOnOver("divC"); //这个是直接到Ext.ComponentManagerMap中拿,没有的话,就用第一个到页面中拿,再返回 var input01 = Ext.get("input01"); var fn1 = function(){ alert("单击B按钮调用这个函数") } //给一个输入框添加键盘B键响应功能 //key是你要触发的那个键,ctrl是否需要与ctrl键结合,fn是触发函数 input01.addKeyMap({key:Ext.EventObject.B,ctrl:false,fn:fn1,scope:input01}); //和上面一本一样,只是添加更加复杂的,处理起来更加方便 /*第一个触发条件的参数是一个对象(条件可以进行组合): {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}*/ //第二个是触发函数fn input01.addKeyListener({key:Ext.EventObject.X,ctrl:true},function(){ alert("单击ctrl+x") },input01); function createChild(){ var el = document.createElement("h5"); el.appendChild(document.createTextNode("我是被追加的")); return el; } Ext.get("div02").appendChild(createChild()); //通过构造对象,来创建DOM Ext.getBody().createChild({ tag:'li', id:'item1', html:'我是第一个个节点' });
Ext.onReady(function(){ //控制元素在指定时间内被单击(当前元素没有数失去焦点) var cl = new Ext.util.ClickRepeater(Ext.get("b4"),{ delay:3000,//首次单击时候的间隔事件 interval:4000,//发生首次重复事件调用之后每一次事件的相隔时间 stopDefault:true,//停止这个el上得默认单击事件 handler:function(){ alert("单击我"); } }); //第一次单击马上会触发事件 如果不去点击其他的元素那么3秒或就会自定执行第二次 //一或会以4秒的间隔执行相应的程序 })
Ext.onReady(function(){ var runner = new Ext.util.TaskRunner(); var task = { run:function(){ Ext.getDom("t1").value = Ext.util.Format.date(new Date(),"Y-m-d-s"); }, interval:1000 } runner.start(task); Ext.get("b6").on("click",function(){ runner.stop(task); }) })