[英]ExtJs best practices
似乎大多数ExtJS书籍和ExtJS介绍只关注显示所有不错的功能,但大多数并没有真正解释如何使用ExtJS构建稳定,可维护的布局/应用程序。 如何写它们而不会造成难以理解的混乱......
我没有特定的应用程序,我只是想知道如何“美化”我的ExtJS代码。 因此,如果您需要一个示例,项目管理(库)或类似工作板的“常规”应用程序将最好地描述我的想法。
因此,当我想使用ExtJS为客户端代码构建这些应用程序时,任何人都可以分享一些关于如何构建这些应用程序的良好链接或建议吗?
提前谢谢,干杯
在我的公司主要代码审查员执行:
作为遵循文档的几个主要规则...... :)
关于十大最差实践的Sencha博客文章值得一读。
博客文章摘要
**请注意,所有信用均归原始博文的合法所有者所有。
1.组件结构的过度或不必要的嵌套
有时开发人员使用冗余嵌套组件,这可能会在应用程序中产生意外的不吸引人的美感,例如双边框或意外的布局行为。
坏
items: [{
xtype : 'panel',
title: ‘My Cool Grid’,
layout: ‘fit’,
items : [{
xtype : 'grid',
store : 'MyStore',
columns : [{...}]
}]
}]
好
layout: ‘fit’,
items: [{
xtype : 'grid',
title: ‘My Cool Grid’,
store : 'MyStore',
columns : [{...}]
}]
在上面的示例中,嵌套面板是冗余的,因为grid是面板的扩展。 此外,其他元素如形状,树木,标签面板是面板的延伸。
2.由于未清除未使用的组件而导致的内存泄漏。
这是有史以来最重要的规则之一。 在任何编程语言中,确保不再使用的组件被正确丢弃是非常非常重要的,即使在Java这样的语言中,GC正在为我们进行所有清理工作,我们应该确保我们不会持有任何编程语言。我们完成它们之后的对象。
坏
Ext.define('MyApp.view.MyGrid',{
extend : 'Ext.grid.Panel',
columns : [{...}],
store: ‘MyStore’,
initComponent : function(){
this.callParent(arguments);
this.on({
scope : this,
itemcontextmenu : this.onItemContextMenu
});
},
onItemContextMenu : function(view,rec,item,index,event){
event.stopEvent();
Ext.create('Ext.menu.Menu',{
items : [{
text : 'Do Something'
}]
}).showAt(event.getXY());
}
});
每次用户右键单击网格行时,都会创建一个新的上下文菜单。 哪个看起来不错,因为我们只看到最新的菜单。
坏(??)
Ext.define('MyApp.view.MyGrid',{
extend : 'Ext.grid.Panel',
store : 'MyStore',
columns : [{...}],
initComponent : function(){
this.menu = this.buildMenu();
this.callParent(arguments);
this.on({
scope : this,
itemcontextmenu : this.onItemContextMenu
});
},
buildMenu : function(){
return Ext.create('Ext.menu.Menu',{
items : [{
text : 'Do Something'
}]
});
},
onItemContextMenu : function(view,rec,item,index,event){
event.stopEvent();
this.menu.showAt(event.getXY());
}
});
这比初始的要好一些。 每当用户右键单击网格视图时,它就会使用相同的菜单对象。 但是,即使我们杀死网格视图,它也会使菜单保持活动状态,这不是我们需要的。
好
Ext.define('MyApp.view.MyGrid',{
extend : 'Ext.grid.Panel',
store : 'MyStore',
columns : [{...}],
initComponent : function(){
this.menu = this.buildMenu();
this.callParent(arguments);
this.on({
scope : this,
itemcontextmenu : this.onItemContextMenu
});
},
buildMenu : function(){
return Ext.create('Ext.menu.Menu',{
items : [{
text : 'Do Something'
}]
});
},
onDestroy : function(){
this.menu.destroy();
this.callParent(arguments);
},
onItemContextMenu : function(view,rec,item,index,event){
event.stopEvent();
this.menu.showAt(event.getXY());
}
});
在上面的视图中,当网格被销毁时,我们也会破坏菜单。
3.怪物控制器
有些人像怪物一样编码......开玩笑,但是有一些大型控制器(不只是控制器,其他组件也是如此:))由数千行代码组成,完成所有那些根本没有关系的东西。
在项目开始时找到一种将应用程序分解为不同处理单元的方法非常重要,这样您就不会得到一个处理应用程序中所有进程的巨型控制器。
建议:
通过不同的方式分解你的申请
APP功能(在订单处理应用程序中 - >订购,交付,客户查找等)
视图(网格,表格等)
在ExtJS中,控制器可以相互通信。
this.getController('SomeOtherController').runSomeFunction(myParm);
也可以触发任何控制器可以侦听的应用程序级事件。
MyApp.getApplication().fireEvent('myevent');
另一个控制器监听app级事件。
MyApp.getApplication().on({
myevent : doSomething
});
4.源代码的文件夹结构不佳
在任何应用程序中,良好的结构都非常重要,因为它提高了项目的可读性和可维护性。 不是将所有控制器放在一个文件夹中,而是将所有视图放在另一个文件夹中,最好根据它们的功能逻辑地构造它们。
5.使用全局变量
为什么使用全局变量是不好的? 有时它不清楚它所拥有的实际价值,因此它可能导致许多混淆,如
很难在运行时发现很难调试的bug
我们对于它可以做些什么呢? 我们可以为它们定义一个单独的类并将它们存储在其中。
5.1首先,我们创建一个单独的javascript文件,其中包含在使用应用程序时需要更改的变量。
Runtime.js
5.2定义一个类来保存全局可用数据,在本例中为“myLastCustomer”变量
Ext.define('MyApp.config.Runtime',{ singleton : true, config : { myLastCustomer : 0 // initialize to 0 }, constructor : function(config){ this.initConfig(config); } });
5.3然后在整个申请过程中提供可用的变量
Ext.application({ name : 'MyApp', requires : ['MyApp.config.Runtime'], ... });
5.4每当你想获取或设置全局变量值时
5.4.1设置值
MyApp.config.setMyLastCustomer(12345);
5.4.2获取价值
MyApp.config.getMyLastCustomer();
6.在组件中使用id是个坏主意?
为什么?
6.1因为您定义的每个id都应该是唯一的。 在大型应用程序中,这可能会导致许多混淆和问题。
6.2很容易让框架处理组件的命名
// here we define the first save button
xtype : 'toolbar',
items : [{
text : ‘Save Picture’,
id : 'savebutton'
}]
// somewhere else in the code we have another component with an id of ‘savebutton’
xtype : 'toolbar',
items : [{
text : ‘Save Order’,
id : 'savebutton'
}]
在上面的示例中,有两个具有相同名称的按钮,这会导致名称冲突。 要防止它,请使用“itemId”而不是id。
xtype : 'toolbar',
itemId : ‘picturetoolbar’,
items : [{
text : 'Save Picture',
itemId : 'savebutton'
}]
// somewhere else in the code we have another component with an itemId of ‘savebutton’
xtype : 'toolbar',
itemId: ‘ordertoolbar’,
items : [{
text : ‘Save Order’,
itemId: ‘savebutton’
}]
现在,您可以按照下面的唯一名称访问上述组件
var pictureSaveButton = Ext.ComponentQuery.query('#picturetoolbar > #savebutton')[0];
var orderSaveButton = Ext.ComponentQuery.query('#ordertoolbar > #savebutton')[0];
// assuming we have a reference to the “picturetoolbar” as picToolbar
picToolbar.down(‘#savebutton’);
7.组件的不可靠引用
使用组件定位来获取对组件的引用不是一个好主意。 因为某人可能会更改组件的位置而不知道它是通过定位在应用程序的另一部分中而引用的。
var mySaveButton = myToolbar.items.getAt(2);
var myWindow = myToolbar.ownerCt;
我们如何获得参考? 使用“ComponentQuery”或“up”/“down”方法。
var pictureSaveButton = Ext.ComponentQuery.query('#picturetoolbar > #savebutton')[0]; // Quering against the itemId
var mySaveButton = myToolbar.down(‘#savebutton’); // searching against itemId
var myWindow = myToolbar.up(‘window’);
8.愿意遵循大/小写命名惯例
使用良好的命名约定作为最佳实践非常重要,因为它可以提高代码的一致性并使其易于阅读和理解。 同样重要的是为您定义的所有类,变量和方法使用有意义的名称。
坏
Ext.define(‘MyApp.view.customerlist’,{ // should be capitalized and then camelCase
extend : ‘Ext.grid.Panel’,
alias : ‘widget.Customerlist’, // should be lowercase
MyCustomConfig : ‘xyz’, // should be camelCase
initComponent : function(){
Ext.apply(this,{
store : ‘Customers’,
….
});
this.callParent(arguments);
}
});
好
Ext.define(‘MyApp.view.CustomerList’,{ // Use of capitalized and then camelCase
extend : ‘Ext.grid.Panel’,
alias : ‘widget.customerlist’, // use of lowerCase
myCustomConfig : ‘xyz’, // Use of camelCase
initComponent : function(){
Ext.apply(this,{
store : ‘Customers’,
….
});
this.callParent(arguments);
}
});
9.将组件约束到父组件布局。
坏
Ext.define('MyApp.view.MyGrid',{
extend : 'Ext.grid.Panel',
initComponent : function(){
Ext.apply(this,{
store : ‘MyStore’,
region : 'center',
......
});
this.callParent(arguments);
}
});
“MyGrid”面板布局区域设置为“中心”。 因此它不能在“西方”等其他地区重复使用。 因此,重要的是以一种可以在任何问题中重复使用的方式定义您的组件。
坏(??)
Ext.define('MyApp.view.MyGrid',{
extend : 'Ext.grid.Panel',
initComponent : function(){
Ext.apply(this,{
store : ‘MyStore’,
......
});
}
});
Ext.create('MyApp.view.MyGrid',{
region : 'center' // specify the region when the component is created.
});
还有另一种方法可以定义具有默认值的组件(在本例中为“region”属性),并在默认值需要更改时覆盖默认值。
好
Ext.define('MyApp.view.MyGrid',{
extend : 'Ext.grid.Panel',
region : 'center', // default region
initComponent : function(){
Ext.apply(this,{
store : ‘MyStore’,
......
});
}
});
Ext.create(‘MyApp.view.MyGrid’,{
region : ‘north’, // overridden region
height : 400
});
10.使代码更加复杂。
有许多方法可以使简单的代码变得复杂。 许多方法之一是通过单独访问表单中的每个字段来加载表单数据。
坏
// suppose the following fields exist within a form
items : [{
fieldLabel : ‘User’,
itemId : ‘username’
},{
fieldLabel : ‘Email’,
itemId : ‘email’
},{
fieldLabel : ‘Home Address’,
itemId : ‘address’
}];
// you could load the values from a record into each form field individually
myForm.down(‘#username’).setValue(record.get(‘UserName’));
myForm.down(‘#email’).setValue(record.get(‘Email’));
myForm.down(‘#address’).setValue(record.get(‘Address’));
好
items : [{
fieldLabel : ‘User’,
name : ‘UserName’
},{
fieldLabel : ‘Email’,
name : ‘Email’
},{
fieldLabel : ‘Home Address’,
name : ‘Address’
}];
myForm.loadRecord(record); // use of "loadRecord" to load the entire form at once.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.