配置项是在创建组件时生成,相当于构造函数的参数;属性是在组件创建后能取到的组件属性,相当于成员变量
controller的init方法优先于application的launch方法执行,而Ext.onReady方法是在页面加载完DOM后执行,延迟加载(不需要加载图片 )
Ext.util.Observable.js是extjs的自定义事件 和Ext.EventMangement.js解决浏览器对事件兼容问题,和对原始事件的封装
extjs利用on方法绑定事件时,参数scope默认是触发该事件的对象this,实际开发中,可以将这个scope复写为其他任意组件;single默认为false,比如渲染renderer这类事件,只需要渲染一次,可以将事件定义为只触发一次,节约内存资源。
myGridPanel.on('hide',this.handlerClick,this,{ single:true, delay:100 }) on方法参数分别为eventName,fn,scope,options(scope:'',delay:'',single:'',buffer:'',target:'',element:'')
另外,Events中有些事件参数有Ext.EventObject,可以使用e.getTarget获得触发事件的组件
Ext.define('Btn',{ extend:'Ext.button.Button', initComponent:function(){ alert('后初始化部件启动...'); }, constructor:function(){ this.text = new Date(); this.renderTo = Ext.getBody(); this.callParent(); alert('先构造函数启动...'); } }); Ext.onReady(function(){ Ext.create('Btn'); });
proxy:{ type:'ajax', api:{ read:'url1', update:'url2' create:'url3', Destory:'url4' } reader:{ root:'', url:'', successProperty:'success' } }
this.getStore().sync()
在grid的columns里面配置数据变量,配置autoScrll:true,scroll:true后不会出现滚动条,但是写死又可以,不知道什么情况
可以控制具体是x方向还是y方向有滚动条overflowX:'auto'或者overflowX:'auto'
注意:后台传过来的json格式,如{success:ture,data:{xx:xxx,……}},与grid不同
myFormPanel.getForm().submit({//提交 //clientValidation: true, url: 'xxx.action', params: { newStatus: 'delivered' }, success: function(form, action) { Ext.Msg.alert('Success', action.result.msg); }, failure: function(form, action) { Ext.Msg.alert('Failure', action.result.msg); }, })
myFormPanel.getForm().load({//加载 url: 'xxx.action', params: { consignmentRef: myConsignmentRef }, failure: function(form, action) { Ext.Msg.alert("Load failed", action.result.errorMessage); } });
注意:后台传过来的json格式,如{total:12,rows:[{xx:xxx,……},{}]},与form不同
myGridPanel.store.load({ params:{params:xx} });
默认参数提交,即每次请求都会提交的参数
myGridPanel.store.proxy.extraParams={xxx:xx}
Ext.Ajax.request({ url: 'xxx.action', params: { id: 1 }, success: function(response){ var text = response.responseText; // Ext.JSON.decode(text) } });
有时候form表单中不想用户编辑。disable:true,视图变灰,而且提交没有此域;而readOnly可以提交
有时候需求为:gridPanel的列不固定,需要动态实现,则可以采用如下方法
创建一个空gridPanel,store:null,columns:[]
通过ajax请求获取columns,并构建相应的store
myGridPanel.reconfigure(store,columns)
根据id找组件:Ext.getCmp('id')
某组件上面的组件 MyCom.up('form');某组件下面的组件MyCom.down('form');
某组件的父和兄弟:MyCom.ownerCt;MyCom.nextSibling();MyCom.previousSibling();
//checkbox放在最后一栏需要配置:injectCheckbox : Number/String
selModel : Ext.create('Ext.selection.CheckboxRowModel',{injectCheckbox : 'last'}),
multiSelect:'MULTI'
extjs4大型项目一般采用MVC模式,事件触发写在controller(详情见API中Ext.app.Controller),根据别名作为选择器如:
Ext.define('MyApp.controller.Users', { extend: 'Ext.app.Controller', models:[], stores:[], views:['myaliasname'], init: function() { this.control({ 'myaliasname': { render: this.onPanelRendered } }); }, onPanelRendered: function() { console.log('The panel was rendered'); } });
一些比较简单的事件,可以使用listeners属性完成 ,如:
listeners: { click: { element: 'el', fn: function(){ console.log('click el'); } }, dblclick: { element: 'body', fn: function(){ console.log('dblclick body'); } } }
或者handler属性,一般是按钮,combobox等组件,和listeners类似
Ext.define('SmartPhone', { config: { hasTouchScreen: false, operatingSystem: 'Other', price: 500 }, isExpensive: false, constructor: function(config) { this.initConfig(config); }, applyPrice: function(price) { this.isExpensive = (price > 500); return price; }, applyOperatingSystem: function(operatingSystem) { if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) { return 'Other'; } return operatingSystem; } }); var iPhone = new SmartPhone({ hasTouchScreen: true, operatingSystem: 'iOS' }); iPhone.getPrice(); // 500; iPhone.getOperatingSystem(); // 'iOS' iPhone.getHasTouchScreen(); // true; iPhone.hasTouchScreen(); // true iPhone.isExpensive; // false; iPhone.setPrice(600); iPhone.getPrice(); // 600 iPhone.isExpensive; // true; iPhone.setOperatingSystem('AlienOS'); iPhone.getOperatingSystem(); // 'Other'
18.extjs对象中配置static中的方法为静态方法:
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');
添加:
方法一:在父组件容器里面配置空items,即items:[],—>创建的子组件—>像操作数组一样push到父容器内,父容器.push(子容器)—>父容器重新渲染一次,父组件.doLayout()
方法二:创建的子组件—>调用父容器的add方法,父容器.add(子组件)
删除:
1.针对添加方法一的删除:
将items内的子组件删除:var destroyItem = 父容器.items.items.pop()—>destroyItem.destroy()
2.针对添加方法二的删除:
直接调用父容器的remove方法:父容器.remove(子组件),子组件内可以配置itemId则父容器.remove(‘itemId’)
1.将json格式的字符串转换为json对象
Ext.JSON.decode(string)
JSON.parse(string)
eval("("+string+")");//注意eval里面有括号
2.将json对象转换为json格式的字符串
Ext.JSON.encode(json)
JSON.stringify(json)
store.load({ scope: this, callback: function(records, operation, success) { // 数据加载后后继操作 console.log(records); } });
注意console.log()和alert()的区别,console.log()显示的为打印的最终结果,类似异步执行;alert停在当前,后面的语句不会执行。如果需要等待(延迟渲染、ajax异步请求),可以使用setTimeout(function(){},1000),在function里面写好需要执行的语句
组件创建后未销毁,一般这些组件继承Ext.Component,它在创建时会注册到Ext.ComponentMgr中(所以在检查组件销毁,可以执行Ext.ComponentMgr.getCount()或ComponentMgr.each(function(key,value,length){console.log(key)})查看组件),不调用destroy方法是不会从中移除的,所以它永远不会被释放。一般调用removeAll方法(abstractContainer子类,比如panel)可以实现级联销毁。也可以在initComponent,destroy事件中递归执行destroy()方法。对于组件销毁了查看store的销毁情况,Ext.data.StoreManager.getCount或each。默认store的配置autoDestroy为ture,extjs4后改为私有方法。默认组件销毁,store也跟着销毁了。如果store里面配置了storeId,store实例会在storeManager中保留,需要手动销毁!Ext.data.AbstractStore的源码:
destroyStore: function() { var me = this; if (!me.isDestroyed) { if (me.storeId) { Ext.data.StoreManager.unregister(me); } me.clearData(); me.data = me.tree = me.sorters = me.filters = me.groupers = null; if (me.reader) { me.reader.destroyReader(); } me.proxy = me.reader = me.writer = null; me.clearListeners(); me.isDestroyed = true; if (me.implicitModel) { Ext.destroy(me.model); } else { me.model = null; } } }
extjs的委托应该是事件冒泡的演变(不确定),一个委托模式的示例是工具条有10个按钮,而你希望在用户将鼠标移动到按钮上面时,为每个按钮委派一个Ext.Tooltip,而且每个Ext.Tooltip都显示不同的文本。如果你创建10个Ext.Tooltip并委派给10个按钮,那么它不是一个优化的解决方案。你只需要创建一个Ext.Tooltip并委派给10个按钮的父元素,也就是工具条。当用户将鼠标移动到工具条上方时,你可以显示相同的Ext.Tooltip,但其文本可根据目标元素(实际上就是按钮)而显示不同的文本(越多getTarget方法可了解如何获取目标元素)。使用这个技术,只需要创建1个Ext.Tooltip,而且只需要在工具条绑定一个监听事件。这可节省内存使用,而且在你的应用运行时实现了相同的效果。找到示例中Ext.Tooltip的delegate属性信息
new,Ext.create方法先将class加载到内存,渲染时直接使用。会引起两个方面的问题。1.在渲染时访问其他组件可能引起null,因为其他组件不一定已经渲染。2.new和create方式容易导致内存泄漏。xtype实现了组件懒初始化,xtype先标识是哪个class,渲染时才将class加载到内存。new引起的内存泄漏的例子:
如 tbar = [new TextField({...})],tbar所在的Grid作为TabItem,并且该TabItem延迟渲染,那么由于new TextField({...})已经注册,但因为未渲染,toolbar中未添加该Field为其Item,导致未销毁组件。(解决办法:通过复写onDestroy主动销毁,或是使用{xtype:""}延迟组件创建),总之,如果主动new ...的组件,那么注意销毁时,是否销毁了相应的组件
xtype的含义
1、减少组件的嵌套
2、尽可能延迟HTMLElement的创建
DOM操作(读/写)的开销一向是昂贵的,尤其在IE6,读取DOM总会引起回滚。因此,经验法则是:尽可能延迟HTMLElement的创建 。以下是实现方式:
●组件Lazy初始化,这在xtype里可实现。
●尝试在渲染后(afterrender)后再执行昂贵的操作。
●避免在组件的构造函数或initComponent方法中对其它组件进行不必要的实例化或渲染。
泄漏分类与解决思路
在combo的change事件中获取兄弟节点引起找不到兄弟节点。以为combo在渲染之后值就已经改变了,则执行change事件。而此时兄弟节点不一定渲染完毕。解决办法:在change事件前面判断value是否为空,是则return。
先获取需要改变的节点(如itemclick事件,treePanel.getSelectionModel().getSeslection()获取target),获取的节点应该是Ext.data.Store.ImplicitModel(继承自Ext.data.Record也就是Ext.data.model),使用set('text','修改后需要显示的文字')方法,但是此时数据是dirty的,需要再次调用Model的commit方法。
虽然在store的model中配置idProperty作为“主键”去重,但是类似在多个combobox引用同一个store的场景下会造成重复项问题。
var store = Ext.create('Ext.data.Store', { listeners: { load: function (store,records,successful) { vat me = store; var k, repeat = [], state = {}; me.each(function (r) { k = r.get('需要去重复的键名称'); if (state[k]) repeat.push(r); else state[k] = true; }); me.remove(repeat); } } });
笔记:
未完待续。。。