2019年3月11日 星期一

jQuery UI 學習筆記 (三) : 對話盒 (Dialog)

人機介面最常用的介面就是對話盒 (Dialog Box), 我找到三篇 2013 年寫的相關舊作, 但那時只是在趕專案情況下倉促所做的紀錄, 我想在這基礎上重寫, 這樣比較完整, 參考 :

jQuery UI 訊息盒 (Msgbox) 語法
# jQuery UI widget 之訊息盒與輸入盒應用範例
jQuery UI widget 之確認盒應用範例

對話盒基本上可分為下列 3 種 :
  1. 訊息盒 (Message Dialog) :
    告知或通知訊息用, 按鈕選項只有一個 OK 或確定鈕, 只能按此關閉訊息盒.
  2. 確認盒 (Confirm Dialog) :
    要求使用者確認某個決定, 至少有 YES/NO 兩個選項按鈕, 一般是 YES/NO/CANCEL 三個按鈕.
  3. 輸入盒 (Input Dialog) :
    要求使用者輸入資訊, 例如帳號密碼, 搜尋關鍵字, 選擇選項等, 因此必須要有輸入欄位, 單選或複選選項, 或者下拉式選單, 以及一個 OK 或確定按鈕.
這三種對話盒結構上分成 HTML 容器與 Javascript 控制這兩部分. 在 HTML 部分都是以 div 網頁元素當作容器, 其 title 屬性就是對話盒的標題, 其內容就是欲告知使用者之訊息, 可以是 HTML 也可以是純文字, 重點是此 div 一定要有一個 id 屬性, 因為這是它能華麗變身的鑰匙 :

<div id="dialog" title="標題"> 
    對話內容 
</div> 

其次 Javascrript 部分是以 div 容器的 id 取得容器之 jQuery 物件, 然後呼叫 其 dialog() 方法並傳入一個設定物件以設定其功能與內容 :

$("#dialog").dialog(configure_object);

此設定物件可分為下面三類 :
  1. Options (選項)
  2. Methods (方法)
  3. Events (事件)
其中 Events 較少用到, 最常用的是 Options 與 Methods. 所謂 Options 事實上就是設定物件中的屬性, 這是建立對話盒時最常用的. 而 Methods 是指對話盒的動作或行為, 常用的是 "open" (開啟對話盒) 與 "close"  (關閉對話盒), 它們是以字串形式傳入對話盒中, 例如 :

$("#dialog1").dialog("open")
$("#dialog1").dialog("close")

參考 :

http://api.jqueryui.com/dialog/

比較常用的 Options 整理如下表 :

 常用設定屬性 說明
 title 對話盒標題 (= div 容器之 title 屬性)
 width 對話盒寬度
 height 對話盒寬度
 modal  是否為強制視窗 (true/false), 預設為 false
 autoOpen 是否自動開啟 (true/false), 預設為 true
 buttons 定義按鈕與其回呼函數等 (陣列或物件)
 beforeClose 定義對話盒關閉前之回呼函數

其中需特別注意的是 :
  1. 對話盒的標題可在 dialog() 的 title 屬性或在 div 的 title 屬性中定義. 
  2. autoOpen 屬性預設是 true, 通常都必須設為 false.
  3. modal 屬性預設是 false.
以下測試均在下列網頁架構下進行, 每個範例僅列出關鍵代碼或程式碼 :

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery UI 測試</title>
  <script src="jquery.min.js"></script>
  <script src="jquery-ui.min.js"></script>
<link id="theme" href="themes/hot-sneaks/jquery-ui.min.css" rel="stylesheet">
  <style>
    body {
      font-family: Arial, Helvetica, sans-serif;
      font-size:10px;
      }
  </style>
</head>
<body>
  <script>
    $(document).ready(function(){
      //
      });
  </script>
</body>
</html>


一. 訊息盒 :

訊息盒只有通知功能, 其訊息通常是包在 div 內的 p 元素內, 例如 :

測試 1 : 訊息盒測試 : 沒有傳入設定物件 [看原始碼]

  <div id="hello" title="Info">
    <p>Hello World! 您好</p>
  </div>
  <script>
    $(document).ready(function(){
      $("#hello").dialog();
      });
  </script> 

此處呼叫 dialog() 時沒有傳入設定物件, 因此網頁一開啟即依照預設值自動彈出一個非強制的對話盒, 按右上角的叉叉即可關閉對話盒. 執行結果如下 :




此訊息盒為非強制性, 因此可以切換去做別的事. 下面測試則將訊息盒設定為強制性, 並且改以傳入物件之 title 屬性設定訊息盒標題,

另外還可用 buttons 屬性在對話盒右下角添加按鈕, 其屬性值可以是一個物件, 其中每個項目代表一個按鈕, 例如 :

        buttons: {
          OK: function() {
                $(this).dialog("close");
                },
          Cancel: function() {
                $(this).dialog("close");
                }

注意, 鍵加不加引號都是可以的, 即用 OK 或 "OK" 或 'OK' 都可以. 其實 buttons 屬性值也可以是一個陣列, 每個元素代表一個按鈕, 陣列的元素均為物件, 其主要的屬性有 :
  1. text : 設定按鈕上的文字 (字串)
  2. click : 設定 click 事件之回呼函數
上面用物件表示的按鈕用陣列表示如下 :

        buttons: [
            {text: "Ok",
              click: function() {
                    $(this).dialog("close");
                    }
              },
            {text: "Cancel",
              click: function() {
                    $(this).dialog("close");
                    }
              }]

下面範例的 bottons 使用物件設定 :

測試 2 : 訊息盒測試 : 傳入設定物件 [看原始碼]

  <div id="hello">
    <p>Hello World! 您好</p>
  </div>
  <script>
    $(document).ready(function(){
      $("#hello").dialog({
        modal: true,
        title: "Info",
        buttons: {
          Ok: function() {
                $(this).dialog("close");
                }
          }
        });
      });
  </script>

注意, buttons 屬性的值也是物件, 其屬性名稱即為按鈕上的文字, 其值為一個按下此鈕之回呼函數, 此處用 $(this) 取得 div 元素之 jQuery 物件, 然後呼叫 dialog('close') 來關閉對話盒.




注意網頁背景色變成黃色表示此對話盒為強制性.

上面的範例都是網頁一開啟就彈出訊息盒, 不過通常對話盒大都為事件驅動, 例如按下按鈕或超連結時才彈出對話盒, 這時 autoOpen 選項必須設為 false, 等到按鈕或超連結按下時才彈出訊息盒, 例如 :

測試 3 : 訊息盒測試 : 按鈕才彈出訊息盒 [看原始碼]

      $("#open" ).click(function(e) {
      $("#hello").dialog("open");
      e.preventDefault();
        });
      $("#hello").dialog({
        autoOpen: false,
        modal: true,
        title: "Info",
        buttons: {
          確定: function() {
                $(this).dialog("close");
                }
          }
        });

注意, 這裡將按鈕上的文字改用中文, 執行結果如下 :




對話盒的 bottons 屬性值除了上面使用物件來設定外, 也可以使用陣列設定, 將上面範例的 bottons 屬性改為使用陣列設定如下 :

測試 4 : 訊息盒測試 : bottons 為陣列的寫法 [看原始碼]

      $("#hello").dialog({
        autoOpen: false,
        modal: true,
        title: "Info",
        buttons: [
          {text: "確定",
           click: function() {
              $(this).dialog("close");
              }
           }
          ]
        });

結果與上面用物件設定是一樣的. 我比較傾向直接用物件設定, 感覺比較直觀與簡單.


二. 確認盒 :

確認盒用來確認使用者的操作是否要進行, 通常右下方須有兩個按鈕, 例如 "Yes/No" 或 "是/否" 等相反之按鈕, 但要注意, 每一個按鈕的事件處理函數最後一行都必須呼叫 $(this).dialog('close') 來關掉確認盒, 例如 :

        buttons: {
          "是": function() {
                  //do something
                  $(this).dialog("close"); 
                  },
          "否": function() {
                  $(this).dialog("close"); 
                  }

下面範例展示一個刪除資料 (檔案或資料庫的紀錄) 前的確認動作 :

測試 5 : 確認盒測試 (1) [看原始碼]

刪除按鈕與確認盒之 HTML :

  <button id="delete" class="ui-button ui-widget ui-corner-all">刪除資料 <span class="ui-icon ui-icon-trash"></span></button>
  <div id="delete_confirmbox">
    <p>確定要刪除這筆資料嗎?</p>
  </div>

jQuery 程式 :

      $("#delete" ).click(function(e) {
      $("#delete_confirmbox").dialog("open");
      e.preventDefault();
        });
      $("#delete_confirmbox").dialog({
        autoOpen: false,
        modal: true,
        title: "確認刪除",
        buttons: {
          "是": function() {
                  //do data deletion
                  $(this).dialog("close");
                  },
          "否": function() {
                  $(this).dialog("close");
                  }
          }
        });

注意, 此例為主題式按鈕添加了一個 icon 圖像, 詳細用法參考 :

jQuery UI 學習筆記 (二) : 主題式按鈕

執行結果如下 :




若 "YES" 或 "是" 按鈕的事件處理函數很長, 也可以將其移出 dialog() 寫在其前面, 將函數指派給一個變數, 並將此變數作為 "YES" 或 "是" 按鈕的屬性值, 例如 :

測試 6 : 確認盒測試 (2) [看原始碼]

      var do_deletion=function() {
        //do data deletion
        $(this).dialog("close");
        }
      $("#delete_confirmbox").dialog({
        autoOpen: false,
        modal: true,
        title: "確認刪除",
        buttons: {
          "是": do_deletion,
          "否": function() {$(this).dialog("close");}
          }
        });

注意, 事件處理函數務必在呼叫 dialog() 之前定義, 否則會報錯.

三. 輸入盒 (Input Box) : 

輸入盒是人機介面中最重要的, 因為它比確認盒帶給系統的資訊更多, 確認盒只是從使用者那邊取得點頭或搖頭 (Yes/No) 的訊息而已.

輸入盒其實只是依據輸入形式在對話盒容器 div 元素裡面放進不同的輸入元素而已, 常見的輸入元素有下列 5 種 :
  1. 文字欄位 (單行) : 即 type 為 text 的 input 元素
  2. 文字區域 (多行) : 即 textarea 元素
  3. 單選圓鈕 : 即 type 為 radio 的 input 元素
  4. 核取方塊 (多選) : 即 type 為 checkbox 的 input 元素
  5. 下拉式選單 : 即 select 與 option 元素
輸入盒與其他對話盒比較需要注意的是對話框的長寬控制, 必須視輸入元素的長寬與數目先行計算以便設定輸入盒的長寬樣式, 否則會因為出現跳行或捲動軸 (scrollbar) 而破壞布局的美觀.

最常用的輸入元素是文字欄位, 例如登入系統時輸入帳號密碼的對話盒就是經典範例, 例如 :

測試 7 : 輸入盒測試 (1) : 登入系統之帳密 [看原始碼]

HTML 部分 :

  <button id="login" class="ui-button ui-widget ui-corner-all">登入系統</button>
  <div id="login_inputbox">
    <p>請輸入帳號密碼</p>
    <p>帳號 : <input id="account" type="text"></p>
    <p>密碼 : <input id="password" type="password"></p>
  </div>
  <div id="login_result">
    <p>帳號或密碼錯誤</p>
  </div>

jQuery 部分 :

      $("#login" ).click(function(e) {
      $("#login_inputbox").dialog("open");
      e.preventDefault();
        });
      var check_login=function() {
        //check database
        $(this).dialog("close");
        $("#login_result").dialog("open");
        }
      $("#login_inputbox").dialog({
        autoOpen: false,
        modal: true,
        title: "登入系統",
        buttons: {
          "取消": function() {$(this).dialog("close");},
          "確定": check_login
          }
        });
      $("#login_result").dialog({
        autoOpen: false,
        modal: true,
        title: "登入失敗",
        buttons: {
          確定: function() {
                $(this).dialog("close");
                }
          }
        });



此例中有兩個對話盒, 一個是帳密的輸入盒 login_inputbox, 另一個是用來顯示登入結果的訊息盒 login_result, 這是一個假的回應 (只是個模擬而已), 不論輸入甚麼, 一律回應帳密錯誤. 按輸入盒的 "確定" 鈕會執行 check_login() 函數, 正常應該透過 Ajax 查詢資料庫, 然後依據回傳 true 或 false 來決定回應錯誤訊息 (如本例), 還是 redirect 到系統內.

上例中的輸入盒寬度似乎太寬, 與帳密輸入欄位寬度不協調, 這可用 width 與 height 屬性來調整, 在下面範例中僅用 width 調整寬度使其變小, 因高度剛好不需要調 :

測試 7-1 : 輸入盒測試 (2) : 登入系統之帳密 [看原始碼]

      $("#login_inputbox").dialog({
        width:210,
        autoOpen: false,
        modal: true,
        title: "登入系統",
        buttons: {
          "取消": function() {$(this).dialog("close");},
          "確定": check_login
          }
        });




另外一個範例是華氏轉攝氏溫度, 取自以前的舊作, 參考 :

jQuery UI widget 之訊息盒與輸入盒應用範例

此處我想反轉過來, 改成攝氏轉華氏, 其轉換公式為 :

華氏 = 攝氏*(9/5)+32
攝氏 = (華氏-32)*5/9

範例如下 :

測試 8 : 輸入盒測試 (3) : 華氏轉攝氏溫度 [看原始碼]

HTML 部分 :

  <button id="f2c" class="ui-button ui-widget ui-corner-all">攝氏轉華氏</button>
  <div id="f2c_inputbox">
    <p>請輸入攝氏溫度</p>
    <p><input id="c" type="text"></p>
  </div>
  <div id="result_msgbox"></div>

jQuery 部分 :

      $("#f2c" ).click(function(e) {
 $("#f2c_inputbox").dialog("open");
 e.preventDefault();
        });
      var compute=function() {               
        var c=parseFloat($("#c").val());
        var f=c*9/5 + 32;
        f=f.toFixed(1);
        $("#result_msgbox").html("攝氏 " + c + " 度=華氏 " + f + " 度");
        $("#result_msgbox").dialog("open");
        $(this).dialog("close");
        }
      $("#f2c_inputbox").dialog({
        autoOpen: false,
        modal: true,
        title: "資料輸入",
        buttons: {
          "取消": function() {$(this).dialog("close");},
          "確定": compute
          }
        });
      $("#result_msgbox").dialog({
        autoOpen: false,
        modal: true,
        title: "換算結果",
        buttons: {確定: function() {$(this).dialog("close");}}
        });




此例須注意部分是呼叫了 toFixed() 來將浮點數的 f 取四捨五入至指定之小數位數, 因為 Javascript 的 Math.round() 只能取至整數. 其次是呼叫訊息盒 result_msgbox 之 html() 方法將計算結果設定給訊息盒. 參考 :

JavaScript 取小數點

最後來測試以下拉式選單, 單選圓鈕, 多選核取方塊作為輸入形式的範例, 此例是調查使用者對特定水果之喜好與常吃那些水果 :

測試 9 : 輸入盒測試 (4) : 單選複選與下拉式選單 [看原始碼]

HTML 部分 :

  <button id="select_fruit" class="ui-button ui-widget ui-corner-all">水果喜好調查</button>
  <div id="fruit_inputbox">
    <p>1.請選擇最喜歡的水果</p>
    <p>
      <select id="favorite_fruit">
        <option>芭樂</option>
        <option>香蕉</option>
        <option>葡萄</option>
        <option>榴槤</option>
        <option>木瓜</option>
      </select>
    </p>
    <p>2.請選擇最討厭的水果</p>
    <p>
      <input type="radio" name="hatest_fruit" value="芭樂"> 芭樂
      <input type="radio" name="hatest_fruit" value="香蕉"> 香蕉
      <input type="radio" name="hatest_fruit" value="葡萄"> 葡萄
      <input type="radio" name="hatest_fruit" value="榴槤"> 榴槤
      <input type="radio" name="hatest_fruit" value="木瓜"> 木瓜
    </p>
    <p>3.請選擇最常吃的水果</p>
    <p>
      <input type="checkbox" name="often_fruit" value="芭樂"> 芭樂
      <input type="checkbox" name="often_fruit" value="香蕉"> 香蕉
      <input type="checkbox" name="often_fruit" value="葡萄"> 葡萄
      <input type="checkbox" name="often_fruit" value="榴槤"> 榴槤
      <input type="checkbox" name="often_fruit" value="木瓜"> 木瓜
    </p>
  </div>
  <div id="result_msgbox"></div>

jQuery 部分 :

      $("#select_fruit" ).click(function(e) {
      $("#fruit_inputbox").dialog("open");
      e.preventDefault();
        });
      var confirm=function() {               
        var favorite_fruit=$("#favorite_fruit").val();
        var hatest_fruit=$("[name=hatest_fruit]:radio:checked").val();
        var arr=[];
        $("[name=often_fruit]:checkbox:checked").each(function(){
          arr.push($(this).val());
          });
        var often_fruit=arr.join();
        var msg="您最喜歡的水果是 : " + favorite_fruit + "<br>" +
                "您最討厭的水果是 : " + hatest_fruit + "<br>" +
                "您最常吃的水果是 : " + often_fruit;
        $("#result_msgbox").html(msg);
        $("#result_msgbox").dialog("open");
        $(this).dialog("close");
        }
      $("#fruit_inputbox").dialog({
        autoOpen: false,
        modal: true,
        title: "資料選擇",
        buttons: {
          "取消": function() {$(this).dialog("close");},
          "確定": confirm
          }
        });
      $("#result_msgbox").dialog({
        autoOpen: false,
        modal: true,
        title: "選擇結果",
        buttons: {確定: function() {$(this).dialog("close");}}
        });




此例中下拉式選單的取值很容易, 直接呼叫 val() 即可, 但 radio 與 checkbox 就必須使用 jQuery 的過濾器找出選取之項目集後再呼叫 val(), 特別是 checkbox 為多選, 可用 each() 工廠函數去迭代以取出所選取之項目. 注意, radio 與 checkbox 的每個選項的 name 必須一樣, 而且一定要設 value 屬性 (值就是選項之值), 否則呼叫 val() 傳回的值只有 on 而已.

參考 :

核取方塊 Checkbox 的存取方法
# jQuery 之 checkbox 及 radio 取值及設定值的正確方法

3 則留言 :

Things In Life 提到...

謝謝您的教學,受益很多~

小狐狸事務所 提到...

這只是我怕忘記而在學過後整理的筆記, 能幫到你我也很高興.

Things In Life 提到...

非常之感謝,您的筆記邏輯很清楚易懂,感謝您的慷慨教學。