1、過度或不必要的組件嵌套 開發(fā)人員最常犯的錯誤之一就是沒有理由的組件嵌套。這會損耗性能并且導致不夠美觀,比如雙邊框或布局異常等。在下面的例子中,有一個僅僅包含Grid的Panel,在這種情況下,Panel是不必要的。記住像Form、Tree、TabPanel和Grid都繼承自Panel,因此在使用這些組件時,應特別注意不必要的組件嵌套情況。 - items: [{
- xtype : 'panel',
- title: ‘My Cool Grid’,
- layout: ‘fit’,
- items : [{
- xtype : 'grid',
- store : 'MyStore',
- columns : [{...}]
- }]
- }]
BAD:這里的Panel是不必要的。 - layout: ‘fit’,
- items: [{
- xtype : 'grid',
- title: ‘My Cool Grid’,
- store : 'MyStore',
- columns : [{...}]
- }]
Good:Grid是Panel的子類,因此可以直接在Grid上使用Panel的屬性。
2、未清除沒有使用的組件導致內(nèi)存泄露 許多開發(fā)者都想知道,為什么應用使用的時間越長,響應速度就越慢。在應用中未清除沒有使用的的組件是最大的原因。在下面的例子中,每次用戶在Grid的行上點擊右鍵菜單,一個新的Menu實例便會被創(chuàng)建。如果用戶一直使用應用并右鍵點擊了Grid行幾百次,那便會有幾百個Menu實例存在,并且永遠不會被銷毀。對開發(fā)者和用戶來說,應用表面上看起來是正確的,因為只有最后創(chuàng)建的Menu實例才會顯示在頁面上,其余的全都被隱藏了。隨著新的Menu實例被創(chuàng)建而老的又沒有被銷毀,應用消耗的內(nèi)存會持續(xù)保持增長。這最終會導致操作變得越來越慢甚至瀏覽器崩潰。 在初始化Grid的時候,只創(chuàng)建Menu實例一次并在每次用戶右鍵點擊時進行復用,是比較好的一種改善方式。即便如此,當Grid被銷毀時,上下文菜單雖然已經(jīng)不需要了,但卻依然存在。最好的方式是在Grid被銷毀時,上下文菜單也隨之進行銷毀。 - 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());
-
- }
- });
BAD:在每次右鍵點擊時都會創(chuàng)建一個Menu實例,并且永遠不會被銷毀。 - 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,
- destroy: this.onDestroy
- });
- },
-
- 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());
- }
- });
Better:當Grid被銷毀的時候,上下文菜單也隨之進行銷毀。3、巨大的控制器 這是令人驚奇的,我們看到的應用常常會有一個由數(shù)千行代碼組成的巨大控制器。我們傾向于根據(jù)應用程序的功能來拆分我們的控制器,它使導航和維護代碼更容易。很多開發(fā)者喜歡通過視圖來拆分控制器。例如,如果一個應用有一個Grid和一個Form,那么將分別有一個管理Grid和管理From的控制器。只要你能始終保持一致,就沒有一種絕對正確的方式來分離控制器邏輯。另外,控制器可以和另外控制器產(chǎn)生聯(lián)系。下面的代碼將演示如何檢索其他的控制器并調(diào)用其方法。 - this.getController('SomeOtherController').runSomeFunction(myParm);
你可以觸發(fā)一個應用級別的事件,并且任何控制器都可以進行監(jiān)聽。下面的代碼將演示如何在一個控制器中觸發(fā)應用級別的事件,并在另一個控制器中對該事件進行監(jiān)聽。 - MyApp.getApplication().fireEvent('myevent');
觸發(fā)應用級別事件 - MyApp.getApplication().on({
- myevent : doSomething
- });
在另一個控制器中進行監(jiān)聽4、源碼的文件組織較差這并不會影響應用性能和操作,但卻讓人很難理清應用的文件組織結(jié)構(gòu)。隨著應用規(guī)模的擴大,如果你能很好地組織你的源碼,那么在代碼中迅速定位并添加新的特性和方法將變得比較容易。就像下圖所示,很多開發(fā)者會把所有的視圖文件(甚至整個項目)都放在同一個文件夾下。 我們推薦根據(jù)業(yè)務邏輯對視圖文件進行組織分類: 5、使用全局變量 雖然使用全局變量的壞處眾所周知,但我們還是在最近審查的很多項目中看到。使用全局變量的應用存在命名沖突、難以調(diào)試等重大問題。相比使用全局變量,更好的做法是使用類的“properies”,并通過getters和setters來引用這些屬性。例如,為了讓你的應用記住最后被選擇的客戶,你可能會像下面的代碼一樣臨時定義一個變量,這很簡單并且它的值在應用的所有部分都是有效的。 - myLastCustomer = 123456;
BAD:使用全局變量來存儲客戶編號。 更好的實現(xiàn)方式是創(chuàng)建一個類,它持有的屬性可以在全局范圍內(nèi)使用。在這種情況下,我們可以創(chuàng)建一個名為Runtime.js的文件來保存運行時屬性。我們可以把該文件放在config文件夾下: Runtime.js文件內(nèi)容: - Ext.define(‘MyApp.config.Runtime’,{
- singleton : true,
- config : {
- myLastCustomer : 0 // initialize to 0
- },
- constructor : function(config){
- this.initConfig(config);
- }
- });
在應用中引用Runtime.js - Ext.application({
- name : ‘MyApp’,
- requires : [‘MyApp.config.Runtime’],
- ...
- });
Set屬性的值 - MyApp.config.setMyLastCustomer(12345);
Get屬性的值 MyApp.config.getMyLastCustomer(); 6、使用"id" 因為每一個id都必須是唯一的,所以我們不推薦在組件上使用id。在項目中很容易多次使用相同的id,這將導致重復id的DOM(命名沖突)。相反,應該讓框架來為你處理生成id的問題。有了ComponentQuery,就無需為組件定義一個id。下面的代碼演示了在一個應用中存在兩個不同的保存按鈕,它們卻有相同的id,這將導致命名沖突。雖然在下面的代碼中很容易發(fā)現(xiàn)問題,但在一個龐大的實際項目中卻很難。 - // 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'
- }]
BAD:給不同組件定義重復的id將導致命名沖突。 如果你想手動識別每個不同的組件,可以像下面的例子中使用itemId來代替id。這將解決命名沖突的問題,并且仍然可以通過itemId來獲得對組件的引用。 - 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’
- }]
有很多種方式可以通過itemId來獲得對組件的引用,如下面的代碼所示: - 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;
BAD:避免通過組件定位來獲得對它的引用。 相反,應該像下面的代碼中通過ComponentQuery或組件的up/down方法來獲得對組件的引用。通過這種方式,代碼將不太容易被破壞,即使組件的結(jié)構(gòu)或順序發(fā)生了改變。 - var mySaveButton = myToolbar.down(‘#savebutton’); // searching against itemId
-
- var myWindow = myToolbar.up(‘window’);
GOOD:通過ComponentQuery來獲得對組件的引用。 8、沒有遵從有關大小寫的命名約定Ext在命名class、component、properties、xtype等時,遵從特定的大小寫規(guī)范。為了避免混淆和代碼清晰,應該始終遵從一致的命名規(guī)范。 - xt.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);
- }
- });
BAD:與Ext不一致的命名約定。 - Ext.define(‘MyApp.view.CustomerList’,{
- extend : ‘Ext.grid.Panel’,
- alias : ‘widget.customerlist’,
- myCustomConfig : ‘xyz’,
- initComponent : function(){
- Ext.apply(this,{
- store : ‘Customers’,
- ….
- });
- this.callParent(arguments);
- }
- });
GOOD:保持與Ext一致的命名規(guī)范。此外,如果你想要觸發(fā)自定義事件,那事件的名稱應該全小寫。當然,即使你不遵從這些規(guī)范,原有的功能仍然可以正常運行,但是為什么要脫離標準并去寫那些不夠清晰的代碼嗎?
9、限定組件在其父組件中的布局 在下面的代碼示例中,面板將總是擁有"region:center"屬性,因此你將不能在其他布局方位中復用它。 - Ext.define('MyApp.view.MyGrid',{
- extend : 'Ext.grid.Panel',
- initComponent : function(){
- Ext.apply(this,{
- store : ‘MyStore’,
- region : 'center',
- ......
- });
- this.callParent(arguments);
- }
- });
BAD:region屬性不應該在這個地方定義。下面的例子則展示在實例化組件并進行顯示的時候才定義布局屬性,通過這種方式你可以在任何地方復用該組件并且不會被布局屬性限制。 - Ext.define('MyApp.view.MyGrid',{
- extend : 'Ext.grid.Panel',
- initComponent : function(){
- Ext.apply(this,{
- store : ‘MyStore’,
- ......
- });
- }
- });
-
- // specify the region when the component is created...
- Ext.create('MyApp.view.MyGrid',{
- region : 'center'
- });
GOOD:在創(chuàng)建組件實例的時候定義布局屬性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
- });
GOOD:定義默認的布局屬性,然后在需要的時候進行重寫。10、復雜化自己的代碼很多次我們看到的代碼都比實際需要的要復雜,這通常是不完全熟悉每個組件的可用方法的結(jié)果。最常見到的一種情況就是從數(shù)據(jù)記錄中分別去加載每一個表單字段。 - // suppose the following fields exist within a form
- items : [{
- fieldLabel : ‘User’,
- itemId : ‘username’
- },{
- fieldLabel : ‘Email’,
- itemId : ‘email’
- },{
- fieldLabel : ‘Home Address’,
- itemId : ‘a(chǎn)ddress’
- }];
-
- // 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’));
BAD:從數(shù)據(jù)記錄中分別加載每一個表單字段。其實,可以使用loadRecord方法從數(shù)據(jù)記錄中一次性加載所有的表單字段,關鍵是表單字段的name屬性和數(shù)據(jù)記錄字段的name要保持一致。 - items : [{
- fieldLabel : ‘User’,
- name : ‘UserName’
- },{
- fieldLabel : ‘Email’,
- name : ‘Email’
- },{
- fieldLabel : ‘Home Address’,
- name : ‘Address’
- }];
-
- myForm.loadRecord(record);
|