1. 程式人生 > >用 Dojo 和 Ajax 建立可重用和可重新發布的元件

用 Dojo 和 Ajax 建立可重用和可重新發布的元件

用例

developerWorks Ajax 資源中心 
請訪問 Ajax 資源中心,這是與開發 Ajax 應用程式相關的免費工具、程式碼和資訊的一站式中心。活躍的 Ajax 社群論壇 由 Ajax 專家 Jack Herrington 主持,這裡的同行或許可以幫助您解答疑問。  

一個部落格應用程式已經開發完並投入使用了。但是,客戶又提出了一項新要求:在部落格系統中增加郵件功能。客戶已經有一個郵件伺服器,希望以某種方式把這兩個應用程式整合起來。客戶希望: 

每當使用者單擊有效的 URL 時,都給他們提供一個視窗。 
這個視窗包含郵件元件提供的所有選項。 
郵件視窗可以向郵件伺服器傳送郵件。 

挑戰

開發團隊不願意為了新增郵件功能而修改部落格系統的核心功能,因為這樣做的風險太大了。如果開發團隊在開發核心功能時使用了第三方軟體,而這些軟體不允許他們修改原始碼,那麼情況就更加麻煩了。另外,管理人員也反對修改現有的表示層和業務層。


解決方案

開發團隊可以選用兩種方法。圖 1 展示了核心功能和新功能並不緊密整合的方法;體系結構使新功能與核心功能鬆散地耦合:


圖 1. 核心功能和新功能並不緊密整合


圖 2 展示了核心功能和新功能緊密整合的方法;在這個體系結構中,新功能成為核心功能的固有部分。


圖 2. 核心功能和新功能緊密整合


開發團隊決定採用第一種方法(圖 1)。這種方法具備與鬆散耦合體系結構相關的所有優點,比如程式碼可重用性,而且限制了測試所需的工作量。  Dojo
Dojo(即 Unified toolkit)是一個用 JavaScript 編寫的開放原始碼 DHTML 工具包。可以使用 Dojo 在 Web 頁面和支援 JavaScript 的任何其他環境中輕鬆地構建動態功能。通過使用 Dojo 提供的元件,可以提高 Web 站點的易用性、響應性和功能性。可以輕鬆地構建可分解的使用者介面,快速地構建互動式元件和轉換。可以使用 Dojo 提供的低階 API 和相容性層編寫可移植的 JavaScript 並簡化複雜的指令碼。Dojo 提供多個入口點和很有前景的 API,獨立於直譯器,而且非常關注消除使用方面的障礙。在 參考資料 中可以找到更多資訊。 


他們將使用 Dojo 開發元件並以鬆散耦合方式把它們整合到主應用程式中。他們選擇 Dojo 是因為: 

Dojo 是基於 JavaScript 的工具包,能夠滿足對整合簡便性的需求。只需包含 JavaScript,開發人員就可以享受到一個強大 API 帶來的好處,這個 API 對於大多數開發任務應該足夠了。它使團隊能夠開發出功能豐富、外觀漂亮的元件,而且很容易把這些元件整合到應用程式中。

Dojo 支援 Ajax,這意味著應用程式的響應性更好,總體效率更高。更重要的是,可以與主應用程式非常快速地互動。 
Ajax 是一種用來建立互動式 Web 應用程式的 Web 開發技術。它在幕後與伺服器交換少量資料,這樣就不必在使用者每次發出請求時都重新裝載整個 Web 頁面,從而使 Web 頁面顯得響應性更好。這種技術會增加 Web 頁面的互動性、速度、功能和易用性。關於 Ajax 的更多資訊參見 參考資料。 



新增 Dojo 元件

首先,需要設定 Dojo(設定方法參見 參考資料)。在設定 Dojo 之後:

需要建立一個 .js 檔案,這個檔案將包含後面編寫的大多數程式碼。在插入所需的功能時,只需把這個 .js 包含在表示層(jsp、HTML 等等)中。 
為了避免在表示層中包含 Dojo 庫,應該在步驟 1 中建立的 .js 檔案中包含它們。清單 1 給出的示例程式碼啟用了 dojo.js 的包含: 

清單 1. 啟用 dojo.js 的包含

function addOnJsFiles(file)
{
        var scriptTag= document.createElement('script');
        scriptTag.src  = file;
        scriptTag.type = 'text/javascript';
        scriptTag.defer = true;
        document.getElementsByTagName('head').item(0).appendChild(scriptTag);
}

/*Take special care that you have not included the dojo.js in the jsp also, as this
is known to cause problem in IE though it works fine with Firefox. If  you have 
included both dojo.js and the .js file in which this function is to implemented, 
you should remove inclusion of dojo.js from jsp file.*/



根據目錄結構的不同,可能需要像清單 2 這樣呼叫清單 1:



清單 2. 呼叫清單 1 中的功能

addOnJsFiles('js/dojo/dojo.js');  
/* Take care of the directory structure */



通過一個解析機制,可以找到使用者在螢幕上輸入的任何電子郵件地址。可以使用 JavaScript 的正則表示式完成這個任務,如清單 3 所示: 

清單 3. 搜尋所有有效的電子郵件模式

var email = /(([a-zA-Z0-9_\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+)/g



編寫一個程式碼片段,把電子郵件地址包圍在一個標籤標記中,如清單 4 所示: 

清單 4. 替換所有有效的電子郵件模式

var htmlContent = document.body.innerHTML;
htmlContent=htmlContent.replace(email, "<label onclick= 
    "sendmail('$1')\">$1</label>");
document.body.innerHTML=htmlContent;



使用 sendmail 函式包含用來建立和顯示 Dojo 元件的主業務邏輯和程式碼。根據使用的元件和 API,包含元件所需的檔案。清單 5 給出一個示例: 

清單 5. 包含必需的包

dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.Button");
dojo.require("dojo.widget.Editor2");
dojo.require("dojo.widget.Textbox");



即使只需包含特定的元件庫(比如 dojo.widget.Button),也必須包含 dojo.widget.* 等包。這種方式與 Java 和其他語言不一樣。dojo.require 方法將動態地獲取 JavaScript 程式碼並把它們裝載到頁面中。如果沒有包含 dojo.widget.* 和 dojo.widget.Button,就會遇到一個執行時異常,因為還沒有裝載通用的元件庫。

Dojo 提供兩種建立元件的方法: 
在建構函式中傳遞元件的父 id(見清單 6)。這裡的 “父” 是指元件將連線的 DOM 元素。 

清單 6. 建立 Dojo 元件

var tmpDiv = document.getElementById(divid);
var FloatingPaneWidget = dojo.widget.createWidget("FloatingPane", 
        { 
                id:"pane1",windowState:"minimized",
                title:"Send Email", hasShadow: "true", 
                resizable:"true",displayMinimizeAction:"true", 
                toggle:"explode",constrainToContainer: "false" 
        },
        tmpDiv);



以程式方式建立元件並把它們插入 DOM 結構,見清單 7: 

清單 7. 建立 Dojo 元件

var newEditor = dojo.widget.createWidget('Editor2');
var layoutWinEd2 = dojo.widget.createWidget("LayoutContainer",
   {layoutAlign:"top"});
layoutWinEd2.addChild(newEditor);



清單 7 在佈局容器中新增編輯器。為了連線郵件元件,可以包含以下程式碼: FloatingPaneWidget.addChild(layoutWinEd2); 



為了新增業務邏輯(用來發送電子郵件的實際程式碼),Dojo 允許把定製的方法與工具包提供的基本方法連線在一起。連線定製方法所用的程式碼如下: dojo.event.connect(SubmitButtonId,"onClick", "codeForSendingMail"); 



編寫處理 onclick 事件的函式,見清單 8: 

清單 8. 處理事件的示例程式碼

function codeForSendingMail () {
        alert("Special handling for onclick ...");
    ...Your logic goes here





最後,顯示元件: dojo.widget.byId('pane1').show(); 


為了非同步地提交資料,需要使用 dojo.io 庫。這個庫提供一個相當簡單的介面,可以通過 bind 方法非同步地提交表單資料。清單 9 給出一個示例: 

清單 9. 處理事件

var myform = dojo.byId("myform");
dojo.io.bind({
url: xyz.com, 
/* This is not required if the form has an action element defined */
formNode: myform,
method: myform.method,  /* Get or Post */
load: myCallBackFuntion,
error: function(type, error) 

        alert("Error: " + type + "n" + error); 
}        
});



Dojo 支援跨域通訊。因為這個應用程式需要跨不同的域(應用伺服器,郵件伺服器)進行通訊,所以需要使用 Dojo 的 XhrIframeProxy 庫。在前面編寫的 .js 檔案中新增清單 10 中的程式碼。 
在 Dojo 的 bind 函式中包含 dojo.io.XhrIframeProxy,這個庫完成所有 Iframe 工作:dojo.require("dojo.io.XhrIframeProxy"); 





清單 10. Dojo 的繫結呼叫

dojo.io.bind({
  IframeProxyUrl: http://externalDomain/myhtml.html,
  url:http://externalDomain/path/myservlet.do,
  content: 
  {
        To:toVal, From: fromVal, CC: ccVal, BCC:bccVal, Subject: subVal, Message: 
           messageText
  },
  load: showSucessMessage,                                        
  error: showErrorMessage,
  method: 'POST',
  mimetype: "text/html"
});


IframeProxyUrl 是外部域上 HTML 檔案的位置,這個域包含一個實現授權(isAllowedRequest)功能的 .js 檔案。 
externalDomain 域上的 HTML 檔案 myhtml.html 應該包含 .js 檔案或者直接在指令碼標記中實現清單 11 中的函式:



清單 11. 遠端 HTML 應該包含的函式

function isAllowedRequest(request){
        /*
                Return true if you want to allow cross domain interaction, 
                else return false
        */
}