天天看點

如何架構EXTJS項目

翻譯了下面這篇文章,感覺老外說話真是夠啰嗦詳細。很多地方我都隻是意譯了事。

這篇文章其實是說了如何架構Ext項目。印象比較深刻的是Pre-configured classes(預配置類),因為目前我還都隻是直接使用Ext的元件。

原文在這裡http://extjs.com/learn/Tutorial:Writing_a_Big_Application_in_Ext

指南: 用Ext開發大型應用

序言

這篇文章,是給那些不再在一個HTML頁面裡面隻是嵌入一個簡單的Window或form的Ext 2.x使用者,是給那些已經決定了以Ext為未來之路的開發者,以及那些感到自己的應用需要一個結構并正在到處辛苦地搜尋相關文章的人們。

問題産出的原因,和解決這些問題的方式,它們的數量等于面對着這些問題的人數。我下面描述的并不是唯一的解決方式,而我也沒說其它方式就是不好。

我想說的是我這個方法是可行的,結構優美的,容易維護的。

什麼是“大型應用”?

如果你隻有一個Viewport,裡面嵌着一個BorderLayout, grid和form,所有這些都在一個檔案裡面,它是不是大型應用?如果你有數十個裝着grid、form或者border layout的window,分别儲存在數十個檔案中,這才叫做大型應用,是這樣嗎?

上述兩種情況都不能用肯定和否定來回答。什麼時候應用才算是大?答案很簡單:當你感覺到它“大”的時候;當你面對一堆檔案,或想在某個檔案裡面尋找某些代碼片段遇到麻煩的時候;當你難以了解元件間的關系的時候,等等。

我們應該把每個應用都看待成大型應用,把代碼寫好,為它真正變成大型應用做好準備,友善我們加入新的功能,甚至寫一行新的代碼,新的CSS規則。

開發一個新應用的最好你要在腦中想:我正在開發一個大型應用!

檔案與目錄

檔案與目錄是我們最先需要組織的東西。在Apache或者其它HTTP伺服器通常有一個DocumentRoot 的目錄設定,下面的所有子目錄都是基于這個設定。

推薦的目錄結構:

./css (optionally link)
./ext (link)
./img (link)
./js
index.html      

上面的link辨別是指這是一個軟連接配接,指向存有檔案的實際目錄。這樣做的好處是當你下載下傳一個新的Ext版本,并嘗試運作,你隻需要改變連接配接指向到這個新版本的目錄,不必改寫任何一句代碼。如果你的應用沒有什麼異常,就讓新版本運作下去吧。如果新版本并不相容,那麼隻要把連接配接指向舊版本的目錄就可以了。

  • css 裡面放你所有的樣式表。如果你有多個項目共用一個樣式表,例如一組顔色和字型的設定,你可以将這個目錄改用連接配接。
  • ext 連接配接去你的Ext JS庫
  • img 連接配接去你的圖檔目錄。它可以有一個icons子目錄。
  • js 儲存組成這個應用的所有javasript檔案
  • index.html 這是你的應用的入口檔案。你可以對它改名,也可能需要另外一些的檔案去處理登陸驗證等。無論怎樣,我們隻有一個應用程式的入口
  • 其它 你可以建立其它目錄或連接配接,去存放應用程式的其它相關檔案(我有一個./classes目錄)你可以對它們随意命名,但是最好跟你所有的應用程式保持風格一緻。(./server, ./php 是一些不錯的示範)

index.html

最簡單的index.html内容是:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <link rel="stylesheet" type="text/css" href="./ext/resources/css/ext-all.css">
  <link rel="stylesheet" type="text/css" href="./css/application.css">
  <script type="text/javascript" src="./ext/adapter/ext/ext-base.js"></script>
  <script type="text/javascript" src="./ext/ext-all-debug.js"></script>
  <script type="text/javascript" src="./js/application.js"></script>
  <title>A Big Application</title>
</head>
<body></body>
</html>
           

雖然上面的代碼運作無誤,但是我還是建議為所有文檔寫上描述性的頭部注釋到所有檔案。同樣标記結束的注釋也應當寫到檔案中。具體請參考《檔案模式》

js/application.js

我們需要一個檔案來寫onReady函數,讓我們将其命名為application.js吧。它最簡單的内容為:

// vim: sw=4:ts=4:nu:nospell:fdc=4
/**
 * An Application
 *
 * @author    Ing. Jozef Sakáloš
 * @copyright (c) 2008, by Ing. Jozef Sakáloš
 * @date      2. April 2008
 * @version   $Id$
 *
 * @license application.js is licensed under the terms of the Open Source
 * LGPL 3.0 license. Commercial use is permitted to the extent that the 
 * code/component(s) do NOT become part of another Open Source or Commercially
 * licensed development library or toolkit without explicit permission.
 * 
 * License details: http://www.gnu.org/licenses/lgpl.html
 */
 
/*global Ext, Application */
 
Ext.BLANK_IMAGE_URL = './ext/resources/images/default/s.gif';
Ext.ns('Application');
 
// application main entry point
Ext.onReady(function() {
 
    Ext.QuickTips.init();
 
    // code here
 
}); // eo function onReady
 
// eof
           

你的檔案的頭部跟底部注釋可能不同,但你需确定Ext.BLANK_IMAGE_URL指向你的伺服器裡面一個1*1像素的透明圖像。Ext用它來作圖像占位符。如果它指向的路徑有誤,你可能會遇到各種渲染的問題,例如combo觸發時圖像丢失,圖示丢失等等的問題。

同時你需要為你的應用構造一個全局的對象變量(這裡是Application)。

你要確定Ext.onReady是主程式的入口。

css/application.css

你可以将CSS樣式表,如果有的話,放到這個檔案裡面。如果你隻有一兩個CSS定義就沒必要為它們建立一個獨立的檔案了,這樣似乎把它們放在頁頭的<style>标簽裡更好。

隻不過,請記住你正在開發一個大型應用,是以所有東西都要有自己的容身之所。如果你将樣式表放在頁頭,不久後如果你要處理改變這些樣式,你或會忘記它們放在哪裡了。

錯誤的方式

上面這些基本東西都做好後,我們接下來要做什麼?讓我們開始寫代碼吧。于是我們坐下來寫下如下代碼:

var vp = new Ext.Viewport({
     layout:'border'
    ,items:[
        new Ext.grid.GridPanel({
            store:new Ext.data.Store({
                 proxy:new Ext.data.HttpProxy({ ...
           

等等。像這樣我們很快将會有10,000行代碼在我們的application.js檔案中,而這樣并不是我們想要的。很明顯,有些步驟我們遺留了。

正确方式:把它們分離

即使最複雜的一個系統,它都是由一些元素組成功能,再由功能組成子系統,再由子系統組成系統本身。你的應用也不會例外。現在是時候區分開這些功能、元件及它們是如何聯系了。

是以,坐下來,想一想,畫個草圖,寫張清單,無論如何,你都得了解這個系統的構成,至少要了解當中最重要的那些。

預配置類

現在你已經做好系統分析并知道會使用哪些元件,你可以開始寫第一個。但是怎樣寫?最好的方式是使用Ext元件的擴充類,在擴充類裡面寫好所有的設定。這些擴充類我稱為預配置類。它們的目的并不是為基類加入新的方法,而僅僅隻是為基類設定好參數。例如,可以建立一個“Personnel” grid 類, 裡面已經設定column model, store, sorting,editor 等。

如果我們已經有了這個類,我們建立一個Window時就可以這樣:

var win = new Ext.Window({
     title:'Personnel'
    ,width:600
    ,height:400
    ,items:{xtype:'personnelgrid'}
});
win.show();
           

寫一個預配置類

[注意:下面的結構并不在所有的環境下都正确,如是有問題,請參考 this post.]

讓我們看一個例子來讨論:

Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
     border:false
    ,initComponent:function() {
        Ext.apply(this, {
             store:new Ext.data.Store({...})
            ,columns:[{...}, {...}]
            ,plugins:[...]
            ,viewConfig:{forceFit:true}
            ,tbar:[...]
            ,bbar:[...]
        });
 
        Application.PersonnelGrid.superclass.initComponent.apply(this, arguments);
    } // eo function initComponent
 
    ,onRender:function() {
        this.store.load();
 
        Application.PersonnelGrid.superclass.onRender.apply(this, arguments);
    } // eo function onRender
});
 
Ext.reg('personnelgrid', Application.PersonnelGrid);
           

看我們都做了些什麼?把 Ext.grid.GridPanel 擴充為 Application.PersonnelGrid, 并将它注冊一個新的 xtype : personnelgrid.

我們為一個普通的grid設定好我們所需的樣式,從此我們有了一個新的元件,可以在應用程式中随時随地使用。我們可以這樣建立一個執行個體:

var pg = new Application.PersonnelGrid();
           

或者使用xtype(延遲執行個體化)

var win = new Ext.Window({
     items:{xtype:'personnelgrid'}
    ,....
});
           

組織預配置類

上面的代碼不必也不應該在onReady函數裡面運作,因為它與DOM結構毫無關系。它隻是定義了一個javascript對象,是以它應該寫在一個獨立的檔案中(js/Application.PersonnelGrid.js),然後在index.html header裡面引入:

到目前為止一切都被安排得很好,我們隻需繼續寫剩下的預配置類,把它們放到 ./js 目錄,并在index.html引入,用它們的執行個體去組成我們的應用。

感覺良好?

其實,還有很多事情要處理。

元件間的溝通

想像我們需要一個border layout,在左邊面闆有一個超連結清單,在中間面闆有一個tab panel。點選一個超連結後會在中間面闆新打開一個tab。現在好了,我們應該将這個邏輯放在哪裡?事件處理器?構造函數?左面闆?還是中間面闆?

都不是。為什麼?如果我們有一個預配置類建立并顯示這個超連結清單,而我們把上述邏輯在這個類中實作。如果程式中這個中間面闆對象不存在,這些超連結就失效了。

如果我們将邏輯放在中間面闆,結果還是一樣:中間面闆與左面闆必須同時存在。

唯一知道這兩個面闆是否存在的元件是它們的容器border layout. 這裡才是正确的地方。

接下來我們要做的是,border layout 要監聽左面闆的點選事件,如果是超連結被點選了,則在中間面闆打開一個新tab. 具體的例子可以參考這裡Saki's Ext Examples

生産系統環境

當我們繼續開發我們的程式就會大量的引入javascript檔案(我引入了大概80個,而且這個數字每天還在增長)。

最好的方法是以是适當的順序把所有javascript檔案的代碼移到一個大檔案中,并使用javascript縮小工具和壓縮工具。當然,在生産環境中你已經不需要Ext庫的debug版本。

是以在生産系統環境中我們需要引入:

  • ext-all.js
  • app-all.js and
  • application.js

關于最小化源代碼我們有另一章節another tutorial來深入讨論。

結論

到這裡已經差不多了。對于特定的類還有特定的的技術,還有很多其它伺服器端或用戶端的技巧,但是上面提到的是核心的觀點了。

繼續閱讀