2013年10月26日 星期六

ExtJS 4 測試 (一) : 對話框與進度條

一段時間沒注意, ExtJS4 已經升版到 4.2.1 了, 增加與修改了一些功能, 詳見 v.4.2.1 Release Note. ExtJS4 的測試環境架設之前整理過了, 參見  "ExtJS 環境部署" 一文. 為了測試對話框, 我重新下載了新版 ExtJS, 測試環境架設簡要複習如下 :
  1. 下載 ExtJS4.2.1 GPL 版本.
  2. 將下載的 ext-4.2.1-gpl.zip 解壓縮, 可以全部解開 (如果想測試一下範例), 但如果只是要用 ExtJS 來測試學習或開發雛型的話, 只需要解開根目錄下的 ext-all.js 檔與 resources 子目錄即可.
  3. 將解開的 ext-all.js 檔與 resources 子目錄複製到我們的專案目錄 project 的 extjs 目錄下, 例如下列結構 :
    project/extjs-4.2.1/ext-all.js
    project/extjs-4.2.1/resources
    project/alert_1.htm                       
接下來撰寫測試網頁 alert_1.htm, 在網頁中要匯入 ext-all.js 函式庫與所使用之 css 樣式表 :

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>ExtJS4</title>
  <link rel="stylesheet" href="extjs-4.2.1/resources/css/ext-all.css" />
  <script type="text/javascript" src="extjs-4.2.1/ext-all.js"></script>
</head>
<body>
</body>
</html>

或者使用 Sencha 的 CDN 也可以 (目前僅 V4.2.0) :

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>ExtJS4</title>
  <link rel="stylesheet" href="http://cdn.sencha.com/ext/gpl/4.2.1/resources/css/ext-all.css" />
  <script type="text/javascript" src="http://cdn.sencha.com/ext/gpl/4.2.1/ext-all.js"></script>
</head>
<body>
</body>
</html>

這樣就可以開始寫測試碼了. 首先來測試 ExtJS 的訊息框, 用來取代 Javascript 的 alert().
跟 jQuery 類似, 要先等 ExtJS 函式庫載入完成, 再進行 ExtJS 函式呼叫較妥當, 所有的 ExtJS 程式碼應該放在 Ext.onReady(function() {...}) 中的大括弧內, 這跟 jQuery 的 $(document).ready(function(){...}) 是同樣的用法.

寫 UI 最常用的就是對話框, ExtJS 處理對話框的類別是 Ext.MessageBox, 這個類別有一個捷徑別名 Ext.Msg, 可以少打一些字元, 兩者通用, 效果相同. 換言之 :

 Ext.MessageBox=Ext.Msg

其 API 與原始碼詳見 :

http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.MessageBox
# Ext.MessageBox 原始碼

要跳出一個 ExtJS 訊息框非常簡單, 只要呼叫 Ext.MessageBox 類別的 alert() 方法即可, 此 alert() 方法帶兩個必要參數與兩個備選參數, 第一個參數是訊息框標題 (title),  第二個參數是要顯示之訊息, 第三個參數是使用者按對話框內的按鈕後之回呼函式 (傳入按鈕字串), 第四個參數為作用域物件 (預設是 window, 一般設為 this 表示作用域限於物件本身) :

Ext.MessageBox.alert("Title", "Message", [callback(btn)],  [scope]);

Ext.onReady(function() {
      Ext.MessageBox.alert("通知訊息", "您好! Hello World!");
      });

測試範例 1 : http://mybidrobot.allalla.com/extjstest/alert_1.htm [看原始碼]


為什麼需要一個回呼函式呢? 這跟 Ext.MessageBox 類別的實作方式有關, 而且關係到整個商業邏輯, 必須特別注意. 簡言之,  Ext.MessageBox 類別所提供的對話框功能其實只是利用 div 元素套疊與 CSS 樣式在網頁中造出的一個顯示層 (Layer) 而已, 並非針對 Javascript 的 window.alert() 進行加強或改造, 所以本質上跟 window.alert() 不同.

最重要的差異是, Javascript 原生的 alert, confirm 與 prompt 與使用者溝通的方式是同步式的, 亦即它會使程式停住, 等待使用者按下對話框中的按鈕後, 才能繼續往下執行; 但 ExtJS 的 MessageBox 類別則是非同步式的, 它不會卡住程式, 當對話框跳出顯示時, 程式碼仍會繼續往下執行. 這有一些好處, 例如當使用者在對話框中輸入資料時, 程式可以繼續往下執行 Ajax 向遠端伺服器擷取資料或繼續操控 UI 介面. 但是如果你希望 ExtJS 的對話框跟 Javascript 一樣是同步式的, 那麼傳統上對話框關閉後才要執行的邏輯必須放在回呼函式中, 不可以放在對話框後面, 否則那些後續邏輯會跟對話框顯示後馬上執行, 這可能與我們所需的同步邏輯不符. 這種用 callback 函式來模擬同步式處理的方法適用以下的確認框, 輸入框等等 Ext.Msg 類別之物件.

在下列範例二中, 我們在一個 Javascript 的訊息框後面緊接著 ExtJS 訊息框, 必須關閉 Javascript 訊息框後, 才會顯示 ExtJS 的訊息框, 可見 Javascript 的訊息框是 hold 得住的 :

      alert("您好! Hello World!");
      Ext.MessageBox.alert("通知訊息", "這是 ExtJS 的訊息框");

測試範例 2 : http://mybidrobot.allalla.com/extjstest/alert_2.htm [看原始碼]

在下列範例三中, 我們反過來在 ExtJS 訊息框後面緊接著一個 Javascript 的訊息框, 可見這兩個訊息框幾乎是同時出現在網頁中 (事實上是 ExtJS 的先, Javascript 的隨後), 因為 Ext.Msg.alert() 是 hold 不住的 :

      Ext.MessageBox.alert("通知訊息", "這是 ExtJS 的訊息框");
      alert("您好! Hello World!");

測試範例 3 : http://mybidrobot.allalla.com/extjstest/alert_3.htm [看原始碼]

請注意, 因為執行程序已經到 Javascript 的 alert 了, 所以必須先關閉原生訊息框, 才能關得掉 ExtJS 的訊息框. 如果希望等 ExtJS 訊息框關閉後才能顯示 Javascript 訊息框, 就必須將它放在 Ext.Msg.alert() 的回呼函式中才行, 如下列範例 4 所示 (使用匿名函式) :

      Ext.MessageBox.alert("通知訊息",
                                             "這是 ExtJS 的訊息框",
                                             function(btn){
                                                alert("您按了 " + btn + " 鈕");                           
                                                });

測試範例 4 : http://mybidrobot.allalla.com/extjstest/alert_4.htm [看原始碼]

請注意, 訊息框會將使用者在對話框內按下之按鈕 id 傳入回呼函式. 如果使用者按下 ok 按鈕, 傳回值就是小寫字串 "ok"; 如果按右上角的 X 鈕, 則傳回小寫的 "cancel" 字串. 其次, Javascript 原生 alert() 的訊息內容只能顯示純文字, 故範例四中的 HTML 碼沒有效果; 而 ExtJS 所有對話框的訊息內容都可以使用 HTML 碼, 如範例五所示 :

      Ext.MessageBox.alert("通知訊息",
          "這是 ExtJS 的訊息框",
          function(btn){
              Ext.MessageBox.alert("通知訊息","您按了 " + btn + " 鈕");
              });      
          });

 測試範例 5 : http://mybidrobot.allalla.com/extjstest/alert_5.htm [看原始碼]

在範例五中, 我們使用了兩層 ExtJS 訊息框, 第二層因為放在回呼函式, 因此必須等第一層訊息框關閉後才會顯示, 可見按鈕字串 ok 或 cancel 已經變成粗體了.

接下來我們測試一下確認框 (取代 Javascript 的 confirm). 此 confirm() 方法的參數與 alert 一樣 :

Ext.MessageBox.confirm("title", "message", [callback(btn)],  [scope]);

回呼函式 callback 用來處理使用者按了 yes, no 或 cancel 之事件. 按鈕事件物件會將使用者所按的按鈕字串 btn 傳入 callback. 確認框有三個按鈕 Yes, No 與 Cancel (即右上角的叉叉), 但其傳入值一律都是小寫字串 : "yes", "no", 與 "cancel". 如下列範例六, 當按下 yes 鍵後, 便進行資料刪除作業 (略), 然後以訊息框顯示結果.

      Ext.MessageBox.confirm(
          "確認訊息",
            "確定要刪除這筆留言?",
            function(btn) {
               if (btn=="yes") {
                   //delete data ...
                   Ext.MessageBox.alert("訊息", "留言已刪除!");
                   }
              else {
                   Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
              });

測試範例 6 : http://mybidrobot.allalla.com/extjstest/confirm_1.htm [看原始碼]


 

最後來測試一下 ExtJS 的輸入訊息框, 用來取代 Javascript 的 prompt(). 這要呼叫 Ext.MessageBox 的 prompt() 方法, 此方法有兩個必要參數, 四個備選參數, 其中回呼函式 callback 有兩個來自按鈕事件的傳入參數, btn 是標示使用者按哪個按鈕之傳回值 (傳回小寫的 "ok" 或 "cancel" 字串), text 是使用者輸入的字串. 備選參數 multiline=true/false, 用來控制輸入框顯示多行或單行輸入區, 預設是 false (單行). 而參數 value 則是用來設定輸入欄位的預設值.

Ext.Msg.prompt("title", "message", [callback(btn, text)], [scope], [multiline], [value]);

下列範例三我們用華氏轉攝氏換算來說明其用法 :

Ext.MessageBox.prompt("輸入訊息",
                                       "請輸入華氏溫度",
                                       function(button, text) {
                                          if (button=="ok") {
                                              var f=parseFloat(text,10);
                                              var c=Math.round((f-32)*5/9);
                                              var msg="華氏 " + text + " 度=攝氏 " + c + " 度";
                                              Ext.MessageBox.alert("通知訊息",msg);
                                              }
                                         else {return;}
                                         });

測試範例 6 : http://mybidrobot.allalla.com/extjstest/prompt_1.htm [看原始碼]

回呼函式中可以再呼叫訊息框方法, 在範例六中, 當使用者輸入華氏度數, 按下 ok 鍵後, 就呼叫 Ext.MessageBox.alert() 方法來顯示結果. 我在 IE8/Chrome/Firefox 上測試都是如下圖所示, 視覺效果相當一致, 特別是圓角 (round corner) 在 IE8 中還是維持原樣沒變方框, 這是 ExtJS 比 jQuery UI 優勝的地方.



下面範例七測試 multiline=true 的情況, 這時輸入區就變成多行, 亦即變成一個 textarea 元件. 但是如果要在訊息框中顯示輸入的多行資料的話, 必須將純文字的跳行符號 "\n" 全部改成 HTML 的跳行符號 "<br>" :

      Ext.Msg.prompt("輸入訊息","請留言",callback,this,true);
      function callback(btn, text) {
        if (btn=='ok') {
           Ext.Msg.alert("您的留言內容",text.replace(/\n/g,"<br>"));
           } //end of if
        else {Ext.Msg.alert("通知訊息","您按了 " + btn + " 鈕");}
        } //end of function

測試範例 7 : http://mybidrobot.allalla.com/extjstest/prompt_2.htm [看原始碼]

ExtJS 還提供一個比較少用的對話框 wait (等候框), 通常用在上傳檔案或提示需時較久之處理上, 讓使用者不至於認為程式沒在跑. 原生 Javascript 並無等候框, 這是 ExtJS 的設計, 它是在 Ext.MessageBox 內實做了一個進度條, 其呼叫函式 wait 有一個必選參數 message, 用來顯示訊息內容, 其下方會有一個周而復始不間斷的進行條, 備選參數 title 是等候框的標題, 第三個備選參數 configObj 可以是一個設定進度條用的 JSON 物件實體,  也可以是一個 Ext.ProgressBar 類別的物件實例, 最常用的屬性是 text, 用來設定此進行條上的文字.

Ext.Msg.wait("message", ["title"], [configObj]);

請特別注意, 等候框與上面三種對話框的前兩個參數順序顛倒, 它的第一個參數是訊息主體, 第二個參數才是對話框標題. 下面範例八我們用一個 JSON 物件實體來設定進度條 :

Ext.MessageBox.wait("請耐心等候!", "等待訊息",{text: "檔案處理中 ..."});

測試範例 8 : http://mybidrobot.allalla.com/extjstest/wait_1.htm [看原始碼]


注意, 等候框上沒有按鈕可以關閉它, 必須於程式中呼叫 hide() 方法來使其消失. 下列範例九我們用 Javascript 的 setInterval() 定時器在指定時間 (10 秒) 後關閉等候框. 同時也改用 Ext.ProgressBar 物件來設定進度條, 可以發現效果是一樣的 :

      var config=Ext.create('Ext.ProgressBar',{text:"檔案處理中 ..."});
      var wait=Ext.MessageBox.wait("請耐心等候!", "等待訊息", config); 
      var timer=window.setInterval(callback,1000);
      var i=0;
      function callback() {
        if (i>10) {  //處理完畢
            window.clearInterval(timer);  //停止定時器
            wait.hide();  //隱藏等候框
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
           wait.updateText("請耐心等候! (" + i*10 + "%)");
           ++i;
           }    
        }

在上例中, Ext.Msg.wait() 會傳回對話框物件本身, 我們先用 wait 變數紀錄此參考, 定時器 timer 每秒鐘會執行 callback 函式一次, 然後呼叫等候框物件之 updateText() 方法更新訊息內容 (可標示完成度), 當旗標增至 10 次時, 便呼叫 hide() 將 wait 等候框隱藏起來, 達到關閉對話框的效果. 這裡只是模擬測試, 實際上在專案中主要是放在 Ajax 的回呼函式中, 當檔案上傳或處理完畢, 回傳 success 時再關閉等候框. 上例中的進度條物件也可以這樣寫 :

var config=new Ext.ProgressBar({text:"檔案處理中 ..."});

測試範例 9 : http://mybidrobot.allalla.com/extjstest/wait_2.htm [看原始碼]


Ext.ProgressBar 類別用法 

上面我們利用 Ext.ProgressBar 類別來設定等候框中的進度條, 事實上, 這個類別也是可以單獨使用的. 現在暫時岔開一下, 先來看看進度條的用法. 它有兩種操作模式 : 人工模式與自動模式. 在人工模式中, 我們必須利用 updateProgress() 方法自行控制進度條的進度變化, 適合用在可以明確量測進度的作業; 而自動模式不需自行操控進度條, 只要呼叫 wait() 方法, 進度條就會週而復始不停的增量-歸零, 直到偵測到作業結束, 適合用在只能偵測到作業結束, 但無法準確得知目前進度的場合. 

下列範例 10 中, 我們把 Ext.ProgressBar 物件直接描繪在 body 容器裡, 然後用定時器每秒呼叫進度條物件的 updateProgress() 方法, 以人工模式 (manual mode) 直接更改進度條中的顯示文字 :

      var progressbar=new Ext.ProgressBar({
                                           width: 300,
                                           renderTo: Ext.getBody()
                                           });
      var timer=window.setInterval(callback,1000);  //每秒觸發一次
      var i=0;
      function callback() {
        if (i>10) {
            window.clearInterval(timer); //停止定時器
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
          progressbar.updateProgress(i/10, "檔案處理中 ...(" + i*10 + "%)");
          ++i;
          }       
        }

這 updateProgress([value], [message], [animate]) 方法有三個參數, 全都是備選參數, 但第一個參數是進度條的值 value (0~1), 若不給, 進度條就不會顯示前進了, 在上面範例中, 我們用 i/10 計算每秒的更新值. 第二個參數 message 是要顯示在進度條上的字串, 第三個參數是 animate (true/fasle), 控制進度條前進時是否要有動畫效果, 預設 false (其實設為 true 後感覺也沒差多少).


測試範例 10http://mybidrobot.allalla.com/extjstest/progressbar_1.htm [看原始碼]

下列範例 11 我們用三個進度條測試 Ext.ProgressBar 的自動模式, wait() 方法可以用一個 JSON 物件來設定. 其屬性說明如下 :

  1. duration  (單位 ms) :
    設定進度條定時器時間長度, 過了這段時間後, 進度條就會停止不再前進.
  2. interval (單位 ms) :
    設定進度條的更新週期, 也就是幾毫秒前進一格, 可以用來控制進度條的速度. 
  3. increment (單位 : 段數)
    設定進度條之分段數目, 預設值為 10 段

所以將 duration 除以 interval 就會得到定時器時間內, 進度條更新的頻率 (次數), 其值若等於 increment, 則進度條只走一個輪迴; 若為 increment 段數的 2 倍, 進度條就輪迴兩次. 例如第一個進度條 duration=10000, interval=1000, 10 秒內會更新 10 次, 而其 increment 設為 10 段, 剛好一個輪迴. 第二個進度條 interval 改成 500, 10 秒內會更新 20 次, 其 increment 設為 10 段, 因此會走兩個輪迴; 第三個進度條 duration=10000, interval=400, 它在十秒鐘內更新 25 次, 其 increment 設為 25 段, 因此也是一個輪迴. 可見, increment 越大, 進度條走起來就越平順, 愈小就越會跳, 若 interval*increment=duration, 那麼進度條終止時就剛好走一輪.

      var progressbar1=new Ext.ProgressBar({
                                            width: 300,
                                            renderTo: Ext.getBody()
                                            });
      progressbar.wait({
        duration:10000,
        interval:1000,
        increment:10,
        text:"進度條 1 號 ...",
        scope:this,
        fn:function(){
          progressbar.hide();
          }
        });


測試範例 11http://mybidrobot.allalla.com/extjstest/progressbar_2.htm [看原始碼]

當 duration 時間到時, 會呼叫 fn 屬性之回呼函式, 此處呼叫進度條的 hide() 方法可以將其隱藏, 模擬關閉的效果. 注意, 自動模式的進度條如果不給 duration 屬性, 那麼它會變成永不停止, 因為其回呼函式 fn 是靠 duration 控制的計時器來觸發, 沒有 duration 就不會呼叫回呼函式.

在上面範例九, 我們是用 updateText() 方法把 realtime 的進度 (百分比) 顯示在等候框的訊息中, 既然我們也可以傳入 Ext.ProgressBar 物件給等候框, 我們能否像上面範例十獨立的 ProgressBar 物件那樣, 用 updateProgress() 方法更改等候框中進度條的顯示文字呢 (主要是處理進度 % 資訊)? 測試的結果是否定的 (why?). 如下列範例 11 所示 :

      var config=new Ext.ProgressBar({text:"檔案處理中 ..."});
      var wait=Ext.MessageBox.wait("請耐心等候!", "等待訊息", config);
      var timer=window.setInterval(callback,1000);
      var i=0;
      function callback() {
        if (i>10) {
            window.clearInterval(timer); //停止定時器
            wait.hide(); //隱藏等候框
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
          config.updateProgress(i/10, "檔案處理中 ...(" + i*10 + "%)");  //無效果
          ++i;
          }       
        }

測試範例 11http://mybidrobot.allalla.com/extjstest/wait_3.htm [看原始碼]

OK, 上面範例都是直接呼叫對話框, 不過專案中常見的是透過事件觸發, 下面範例 12 我們就把這三個對話框都分別利用一個按鈕的 click 事件來觸發 :

  <input id="btn_alert" type="button" style="width:100px;" value="訊息框">
  <input id="btn_confirm" type="button" style="width:100px;" value="確認框">
  <input id="btn_prompt" type="button" style="width:100px;" value="輸入框">

測試範例 12 : http://mybidrobot.allalla.com/extjstest/dialog_1.htm [看原始碼]

利用 get() 方法取得按鈕物件後, 呼叫 on() 方法綁定一個 click 事件給 callback 函式, 例如觸發訊息框寫法如下 :

      Ext.get("btn_alert").on("click",function(){
         Ext.MessageBox.alert("通知訊息", "您好! Hello World!");
         }); //end of on

這樣就會在按下按鈕觸發 click 事件時顯示對話框. 但請注意, 我特別將 input 按鈕的 width 設為 100px, 因為套用 ExtJS 的 CSS 後, 按鈕邊界會縮到內容寬度與高度, 使得按鈕看起來很小. 其實除了 Apple 瀏覽器外, 瀏覽器所繪製的原生按鈕真的都不怎麼好看, 既然用了 ExtJS, 那麼應該使用 ExtJS 提供的按鈕物件來製作, 不要直接用 HTML 語法寫出按鈕, 這樣在 UI 視覺上比較一致.

ExtJS 製作按鈕元件的語法如下 :

var btn_alert=new Ext.Button({
                                       text : "訊息框",
                                       width : 100,
                                       renderTo : Ext.getBody(),
                                       handler : show_alert
                                       });

var btn_alert=new Ext.Button({
                                       text : "訊息框",
                                       width : 100,
                                       renderTo : Ext.getBody(),
                                       handler : function(btn) {
                                           Ext.MessageBox.alert("通知訊息", "您好! Hello World!");
                                           }
                                       });

其中屬性 text 是顯示在按鈕上的文字, width 是寬度 (px), renderTo 是要把此按鈕描繪在哪一個容器物件上, 這裡 Ext.getBody() 是取得 body 元素, 以便把按鈕放入 body 中; 而 handler (或用 listener 亦可) 則是指定事件處理函式名稱 (不要加括弧), 也可以直接用匿名函式. 我們將範例 11 改寫為範例 12 如下, 其中訊息框採用匿名函式, 其他用外部函式 :

測試範例 12 : http://mybidrobot.allalla.com/extjstest/dialog_2.htm [看原始碼]

這按鈕看起來就比較美觀了. 比較如下 :


以上便是 ExtJS 常用的對話框用法, 這在專案中常常會用到, 是應用程式與使用者溝通的重要介面. 既然使用了 ExtJS 框架, 那麼必須讓使用者有一致的 GUI 介面, 不宜再穿插使用 Javascript 原生的 alert, confirm, 與 prompt 了. 當然呼叫時要敲比較長的指令很不方便, 因此 ExtJS 給 MessageBox提供了 Msg 這個名稱捷徑, 亦即, MessageBox 可以用 Msg 這個捷徑名稱取代 :

Ext.Msg.alert()
Ext.Msg.confirm()
Ext.Msg.prompt()
Ext.Msg.wait()

在使用這四種對話框時, 首先要注意的是, 對話框中的四種按鈕 yes, no, ok, 與 cancel 其傳回值都是小寫的字串, 因此回呼函式中的第一個參數 button 在比對時務必要用小寫的 "yes", 不可以用 "Yes" 或 "YES", 否則你會發現事件根本沒被處理.

以上四種對話框使用上很簡單, 但相對地能設定的項目也較少. 例如沒辦法加上小圖檔. 如果要製作更有彈性地客製化對話框, 就要用更一般的方法 Ext.Msg.show(), 事實上面四種對話框就是用特定之設定值呼叫 Ext.Msg.show() 的.

Ext.Msg.show() 提供了很多屬性, 其中 title (標題), msg (訊息), buttons (按鈕), 與 fn (回呼函式) 是每一種對話框最基本的屬性, 所有的 show() 對話框預設都是強制模式對話框 (modal=true), 所以除非應用上需要非強制對話框, 否則 modal 屬性不需要給.

我們先用 show() 來製作帶有 icon 訊息框, 如範例 13 所示.


測試範例 13http://mybidrobot.allalla.com/extjstest/show_alert.htm [看原始碼]

      Ext.MessageBox.show({
        title: "通知訊息",
        msg: "您好! Hello World!",
        buttons: Ext.Msg.OK,
        icon: Ext.Msg.INFO,
        fn: function(btn) {
          Ext.Msg.alert("通知訊息", "您按了 " + btn + " 鈕");
          }
        });

在上例中, buttons 屬性設為 Ext.Msg.OK, 表示要在訊息框中放置一個按鈕 : Ok. 屬性 buttons 的可能值列於下表.

 buttons 按鈕
 Ext.Msg.OK Ok
 Ext.Msg.CANCEL Cancel
 Ext.Msg.OKCANCEL Ok + Cancel
 Ext.Msg.YES Yes
 Ext.Msg.NO No
 Ext.Msg.YESNO Yes + No
 Ext.Msg.YESNOCANCEL Yes + No + Cancel

而 icon 屬性是用來在訊息 msg 字串前面加上一個圖型, 可用之值如下表 :

icon 圖形
 Ext.Msg.INFO
 
 Ext.Msg.ERROR
 
 Ext.Msg.WARNING
 
 Ext.Msg.QUESTION
 

對於訊息框而言, 可以使用 Ext.Msg.INFO, ERROR, 或 WARNING, 視情況而定.

其次用 show() 來製作確認框, 它需要一個 Question 圖形, Yes 與 No 按鈕, 如範例 14 所示, 其實它跟訊息框的差別就是 icon 部分為 Yes/No, 而非 Ok 而已, 而且要依據使用者按 Yes 或 No 來反應.

測試範例 14http://mybidrobot.allalla.com/extjstest/show_cinfirm.htm [看原始碼]

      Ext.MessageBox.show({
        title: "確認訊息",
        msg: "確定要刪除這筆留言?",
        buttons: Ext.Msg.YESNO,
        icon: Ext.Msg.QUESTION,
        fn: function(btn) {
              if (btn=="yes") {
                  //delete data ...
                  Ext.MessageBox.alert("訊息", "留言已刪除!");
                  }
              else {
                  Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
          }
        });

接著我們用 show() 來製作單行文字輸入框, 它需要一個 INFO 圖形, Ok 與 Cancel 按鈕, 如範例 15 所示.

測試範例 15http://mybidrobot.allalla.com/extjstest/show_prompt_1.htm [看原始碼]

      Ext.MessageBox.show({
        title: "輸入訊息",
        msg: "請輸入華氏溫度",
        prompt: true;
        value: 32,

        buttons: Ext.Msg.OKCANCEL,
        icon: Ext.Msg.INFO,
        fn: function(btn, text) {
              if (btn=='ok') {
                  var f=parseFloat(text,10);
                  var c=Math.round((f-32)*5/9);
                  var msg="華氏 " + text + " 度=攝氏 " + c + " 度";
                  Ext.Msg.alert("通知訊息",msg);
                  } //end of if
              else {Ext.Msg.alert("通知訊息","您按了 " + btn + " 鈕");} 
              } //end of function
        });

下面範例 16 是測試多行輸入框, 這需要將 multilines 屬性設為 true (預設為 false 是單行), 而多行輸入區的高度可以利用 defaultTextHeight 屬性來調整 (預設是 75px) :

測試範例 16http://mybidrobot.allalla.com/extjstest/show_prompt_2.htm [看原始碼]

      Ext.MessageBox.show({
        title: "輸入訊息",
        msg: "請留言",
        prompt: true,
        multiline: true,
        defaultTextHeight: 100,

        buttons: Ext.Msg.OKCANCEL,
        icon: Ext.Msg.INFO,
        fn: function(btn, text) {
              if (btn=='ok') {
                  Ext.Msg.alert("您的留言內容",text.replace(/\n/g,"<br>"));
                  } //end of if
              else {Ext.Msg.alert("通知訊息","您按了 " + btn + " 鈕");} 
              } //end of function
        }); 

最後看看如何用 show() 製作等候框. 要在 show() 方法產生的對話框中出現進度條, 必須將 progress 屬性設為 true (預設 false 不顯示), 這會在對話框的訊息下方顯示一個進度條, 但是, 這個進度條不會動, 必須透過呼叫  Ext.Msg 物件的 updateProgress() 方法去更新進度條的值 (value) 才會動, 所以 progress=true 適合可以掌握精確進度的等候框 (手工控制模式), 如下面範例 16 所示 :

測試範例 16 : http://mybidrobot.allalla.com/extjstest/show_wait_1.htm [看原始碼]

      var wait=Ext.MessageBox.show({ //傳回 Ext.MessageBox 物件
                 title: "等待訊息",
                 msg: "請耐心等候!",
                 width: 300,
                 progress: true
                 });
      var timer=window.setInterval(update,1000);
      var i=0;
      function update() {
        if (i>10) {
            window.clearInterval(timer); //停止定時器
            wait.hide(); //隱藏等候框
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
            wait.updateProgress(i/10, "檔案處理中 ...(" + i*10 + "%)");
            ++i;
            }      
        }

在上面範例中, 我們同時設定了 width 屬性將對話框寬度改為 300px. 但是, 如果只是設定 progress=true 還不夠, 那只是顯示一個不會跑的進度條而已, 你必須 範例 16 中使用一個定時器每秒呼叫自訂的 update() 函式, 呼叫 Ext.Msg 物件的 updateProgress() 方法, 更新其 value 參數值, 這樣進度條才會跑. 這通常是在可以精確掌握進度 (例如檔案處理) 情況時使用; 如果是檔案上傳或資料庫查詢使用 Ajax 無法預知處理進度情況時, 適合使用下列範例 17 會自動跑的等候框 (自動模式), 這就要改用 wait 屬性 (設為 true).

測試範例 17 : http://mybidrobot.allalla.com/extjstest/show_wait_2.htm [看原始碼]

      var wait=Ext.MessageBox.show({
                 title: "等待訊息",
                 msg: "請耐心等候!",
                 width: 300,
                 wait: true,
                 waitConfig: {
                   duration:10000,
                   interval:1000,
                   increment:10,
                   text:"檔案處理中 ...",
                   scope:this,
                   fn:function(){
                        wait.hide();
                        Ext.Msg.alert("通知訊息", "檔案處理完成!");
                        }
                   }
                 });

自動控制模式是將 wait 屬性設定為 true (預設為 false), 這會在對話框的訊息下方顯示一個進度條, 這跟 progress=true 的進度條不同的是, 它會以預設的速度自動前進. 我們可用 waitConfig 設定進度條的文字與速度等屬性, 這跟上面 Ext.ProgressBar 的用法一樣. 在上例中我們用 duration 指定進度條計時器為 10 秒, 用 interval 與 increment 指定速度, 也指定了計時器終止時的回呼函式來隱藏等候框. 實際專案中使用 Ajax 存取資料時, 不需要設定 duration 與 fn, 而是在 Ajax 的 success 等回呼函式中呼叫 hide() 方法來隱藏等候框, 在這之前, 進度條會周而復始地不間斷自動變化. 注意, 設定 wait=true 的等候框沒有右上角的 X (Cancel 鈕), 即使你將 closable 屬性設為 true 亦然 (預設即為 true), 這跟前面 Ext.Msg.wait() 的等候框是一樣的 (別忘了 wait 就是用 show 訂製出來的).

最後, 有沒有發現所有的對話框上的按鈕文字都是英文 (Ok, Yes, No, Cancel)?  有沒有辦法把他們變成 "確定", "是", "否", "取消"? 在 ExtJS 解壓縮檔案中有一個 locale 目錄, 底下有許多語言本土化檔案, 繁中是 ext-lang-zh_TW.js, 但打開該檔案會發現它並沒有處理對話框按鈕文字中文化, 它是給日期選擇器等元件用的. 對話框中文化有兩種作法, 對於 alert(), confirm(), prompt() 這三個訂製型的對話框 (wait 沒有按鈕, 不需中文化), 必須在呼叫方法前設定 buttonText 屬性如下 (注意, key 都是小寫)  :

      Ext.MessageBox.buttonText={ok:'確定',yes:'是',no:'否',cancel:'取消'};
      Ext.MessageBox.alert(
        "通知訊息",
        "這是 ExtJS 的訊息框",
        function(btn){
          Ext.MessageBox.alert("通知訊息","您按了 " + btn + " 鈕");
          });

測試範例 18http://mybidrobot.allalla.com/extjstest/alert_locale.htm [看原始碼]


可見 Ok 按鈕已經變成 "確定" 按鈕了. 雖然在設定時四種按鈕都有設定中文化, 但實際上 alert 只有一個 Ok 按鈕, 所以只顯示確定鈕.

至於使用 show() 製作的對話框也是一樣, 如下列範例 19 所示 :

      Ext.MessageBox.buttonText={ok:'確定',yes:'是',no:'否',cancel:'取消'};
      Ext.MessageBox.show({
        title: "確認訊息",
        msg: "確定要刪除這筆留言?",
        buttons: Ext.Msg.YESNO,
        icon: Ext.Msg.QUESTION,
        fn: function(btn) {
              if (btn=="yes") {
                  //delete data ...
                  Ext.MessageBox.alert("訊息", "留言已刪除!");
                  }
              else {
                  Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
          }
        });

測試範例 19http://mybidrobot.allalla.com/extjstest/show_locale_confirm_1.htm [看原始碼]


特別注意, 上例中 buttonText 屬性必須先設定後再呼叫 Ext.Msg 物件的 show() 方法, 否則中文化c無作用, 仍顯示英文. 其次, buttonText 僅改變按鈕上的顯示文字, 傳入回呼函式的按鈕 id 之值不受影響, 仍是小寫的 ok/yes/no/cancel 字串.

除了上面的方法外, 還可以在設定項中指定 buttonText 屬性, 但是這種做法是用到幾個按鈕就列出幾個, 不要像第一種做法那樣全列, 否則會顯示全部按鈕. 如範例 20 所示 :

      Ext.MessageBox.show({
        title: "確認訊息",
        msg: "確定要刪除這筆留言?",
        buttons: Ext.Msg.YESNO,
        buttonText: {ok:'確定',yes:'是',no:'否'},
        icon: Ext.Msg.QUESTION,
        fn: function(btn) {
              if (btn=="yes") {
                  //delete data ...
                  Ext.MessageBox.alert("訊息", "留言已刪除!");
                  }
              else {
                  Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
          }
        }); 

測試範例 20http://mybidrobot.allalla.com/extjstest/show_locale_confirm_2.htm [看原始碼]


可見雖然 buttons 屬性只設定 Yes 與 No 兩個按鈕, 但是因為 buttonsText 多設定了 Ok, 所以顯示了三個中文化按鈕. 注意, 此處 buttons 與 buttonText 先後順序沒有關係.

以上便是 ExtJS 4 對話框常用方法的測試, 花了我兩周斷斷續續修改, 總算摸出 ExtJS 的一點象尾巴了. 我覺得學習 ExtJS 主要就是要學會其設定方法而已.

沒有留言 :