2019年3月23日 星期六

jQuery UI 學習筆記 (七) : 進度條 (ProgressBar)

在學習 Django 的 Template 過程中發現以前沒有時間寫下 jQuery UI 元件的學習筆記, 這兩周補寫竟然已完成六篇, 原先以為很簡單, 實測後才發現不容易, 當初設計這些 Widget 的人實在令我敬佩.

本篇來到進度條, 這元件通常用在同步傳輸時讓人等待同步完成用的, 例如上傳檔案或進行大量耗時計算時就用得上. 進度條的 API 與教學文件參考 :

https://jqueryui.com/progressbar/
http://api.jqueryui.com/progressbar/
http://tutorialspark.com/jqueryUI/jQuery_UI_Progress_Bar.php

進度條的載體是 div 元素 :

<div id="progressbar1"></div>

然後呼叫 div 的 jQuery 物件的 progressbar() 方法即可 :

$("#progressbar1").progressbar();

例如 :


測試 1 : Progressbar 測試 : 預設進度條 [看原始碼]

如果沒有傳入選項物件的話, 預設進度是 value=0.

常用的選項如下表 :

 常用 options 說明
 value 目前值 (預設 0), 設為 false 表示不確定值
 max 最大值 (預設 100)
 disabled 不可用 (預設 false)

常用的方法如下表 :

 常用 method 說明
 value 取得目前值或設定新值
 option 取得或設定選項之值
 disable 禁能 (等於 disabled 屬性=True)
 enable 致能 (等於 disabled 屬性=False)

常用的事件如下表 :

 常用 event 說明
 create 建立進度條物件時觸發
 change 值已改變且輸入框失焦時觸發
 complete 到達最大值 max 時觸發

建立進度條時可以傳入選項物件, 例如 :


測試 2 : Progressbar 測試 : 傳入選項物件 [看原始碼]

HTML 部分 :

  <div id="progressbar1"></div>
  <p id="display"></p>

jQuery 部分 :

      var config={
        value: 200,
        max: 1000,
        create: function(e, ui) {
          $("#display").html($("#progressbar1").progressbar("value"));
          }
        };
      $("#progressbar1").progressbar(config);




此例我們在進度條下面放置了一個 p 元素來顯示目前之值, 這是在建立元件時 (create 事件) 透過呼叫 value 方法所取得的. 取得現值還可以用 option 方法, 不過還是直接用 value 方法較簡短 :

$("#display").html($("#progressbar1").progressbar("option", "value"));

其實也可以直接將目前進度顯示在進度條內, 這樣就不用另外設置一個 p 元素來顯示了.

在 Chrome 按 F12 進入開發者模式的 "Element" 頁籤, 找到 id=progressbar1 的 div 元素, 可知 jQuery UI 將此 div 渲染後, 其實在裡面又安插了一個 div 元素來顯示進度, 其第一個 class 樣式為 ui-progressbar-value, 而其 style 屬性值為 20% (因為 200/1000=20%) :

<div class="ui-progressbar-value ui-corner-left ui-widget-header" style="width: 20%;"></div>




可直接用此屬性值顯示在進度條內, 不過利用 attr() 方法取出的 style 樣式值是像 "width: 20%;" 這樣的字串, 可用正規表示法取出其中的 "20%" 用來顯示, 例如 :


測試 3 : Progressbar 測試 : 利用進度條本身顯示進度值 [看原始碼]

HTML 部分 :

  <div id="progressbar1"></div>

jQuery 部分 :

      var config={
        value: 200,
        max: 1000,
        create: function(e, ui) {
          var style=$(".ui-progressbar-value").attr("style");
          var percent=style.match(/\d+%/);
          $(".ui-progressbar-value").html(percent);
          }
        };
      $("#progressbar1").progressbar(config);




此例在 create 事件處理函數中, 先用 attr() 取得內部進度條 div 元素的 style 屬性值, 此處即 "width: 20%;", 然後使用 Javascript 的正規式函數 match() 尋找匹配 /\d%/ 的字樣, 其中 \d 表示任何 0~9 數字, 後面則跟著 % 字元, 此處 match() 會傳回 "20%" 給 percent 變數, 這樣就可以呼叫 html() 將其插入內部進度條 div 元素內容裡了.

不過這裡有個問題, 就是 20% 字樣似乎是靠左靠上顯示, 視覺上有點不平衡,  要如何將其垂直置中呢? 使用 vertical-align: middle 對 div 是無效的, 因為這只對 inline 類型元素有效 (例如表格 table 內的儲存格), 而 div 是 block 類型元素, 此樣式對 div 無效.

總之, 水平置中很容易, 只要設定 text-align: center 即可, 但垂直置中就很麻煩, 網路上可找到許多方法, 但大部分看來都很複雜, 參考 :

6 Methods For Vertical Centering With CSS
CSS Layout - Horizontal & Vertical Align
Understanding vertical-align, or "How (Not) To Vertically Center Content"

此文提到一個簡單的垂直置中辦法, 就是使用 line-height, 但前提是要知道父元素的高度, 例如在進度條中須取得內部進度條 div 的高度, 這可以用此元素 jQuery 物件的 height() 方法 :

$(".ui-progressbar-value").height();

在 body 的樣式設定為 style={font-size:10px;} 情形下其傳回值為 24px, 因此只要將內部 div 的 line-height 設為 24px 即可將進度百分比數值置中. 例如 :


測試 4 : Progressbar 測試 : 進度數值置中做法 [看原始碼]

HTML 部分 :

  <div id="progressbar1"></div>

jQuery 部分 :

      var config={
        value: 200,
        max: 1000,
        create: function(e, ui) {
          var style=$(".ui-progressbar-value").attr("style");
          var percent=style.match(/\d+/) + "%";
          $(".ui-progressbar-value").html(percent);
          //alert($(".ui-progressbar-value").height());
          var css={"line-height":"24px","padding-left":"5px"};
          $(".ui-progressbar-value").css(css);
          }
        };
      $("#progressbar1").progressbar(config);



此處除了 line-height 外還添加了 padding-left 樣式使進度值不要太靠近左邊框, 視覺上比較對稱些. 以下範例將以此方式顯示進度數值. 注意, line-height 的屬性值需隨 body 的 font-size 而變 :

font-size=10 : line-height=24
font-size=12 : line-height=28
font-size=14 : line-height=33
.....

例如 :

測試 4-1 : Progressbar 測試 : 進度數值置中做法 font-size=12 [看原始碼]
測試 4-2 : Progressbar 測試 : 進度數值置中做法 font-size=14 [看原始碼]

如果進度數值要水平置中, 只要加上 text-align=center 樣式即可 :

          var css={
            "line-height": "24px",
            "padding-left": "5px",
            "text-align": "center"};

例如 :


測試 4-3 : Progressbar 測試 : 進度數值水平置中做法 [看原始碼]




下面範例測試 option, enable 與 disable 等方法 :


測試 5 : Progressbar 測試 : option, enable 與 disable 方法 [看原始碼]

HTML 部分 :

  <div id="progressbar1"></div><br>
  <button id="toggle" class="ui-button ui-widget ui-corner-all">Toggle</button>

jQuery 部分 :

      var config={
        value: 200,
        max: 1000,
        disabled: true
        create: function(e, ui) {
          var style=$(".ui-progressbar-value").attr("style");
          var percent=style.match(/\d+/) + "%";
          $(".ui-progressbar-value").html(percent);
          var css={"line-height":"24px","padding-left":"5px"};
          $(".ui-progressbar-value").css(css);
          }
        };
      $("#progressbar1").progressbar(config);
      $("#toggle").click(function(e) {
        var isDisabled=$("#progressbar1").progressbar("option", "disabled");
        if (isDisabled) { //現在是不可用狀態
          $("#progressbar1").progressbar("option", "disabled", false);
          //$("#progressbar1").progressbar("enable"); //另一用法
          }
        else {  //現在是可用狀態
          $("#progressbar1").progressbar("disable");
          }
        });




此例放置了一個 Toggle 按鈕, 進度條預設為不可用 (disabled: true), 按 Toggle 按鈕會使其可用, 再按一次又變不可用.

以上範例進度條都固定不動, 實務上會從後端或其他 API 取得進度數據後更新進度條顯示往前增加直到到達 max 所設定之最大值. 下列範例以 setInterval() 函數來模擬實際進度條之變化情形, 參考 :

深入了解 setTimeout() 與 setInterval() 的不同之處


測試 6 : Progressbar 測試 : 使用 setInterval() 模擬進度變化 [看原始碼]

HTML 部分 :

  <div id="progressbar1"></div><br>

jQuery 部分 :

      var config={
        create: function(e, ui) {
          var style=$(".ui-progressbar-value").attr("style");
          var percent=style.match(/\d+%/);
          $(".ui-progressbar-value").html(percent);
          var css={"line-height":"24px","padding-left":"5px"};
          $(".ui-progressbar-value").css(css);
          },
        change: function(e, ui) {
          var style=$(".ui-progressbar-value").attr("style");
          var percent=style.match(/\d+%/);
          $(".ui-progressbar-value").html(percent);
          },
        complete: function(e, ui) {
          var style=$(".ui-progressbar-value").attr("style");
          var percent=style.match(/\d+%/) + " (已完成)";
          $(".ui-progressbar-value").html(percent);
          }     
        };
      $("#progressbar1").progressbar(config);
      var value=0;  //進度條初始值
      var callback=function() {  //回呼函數
        $("#progressbar1").progressbar("value", value);  //更新進度條數值
        ++value;
        if (value >= 100) {clearInter(timer);}  //清除定時器
        };
      var timer=setInterval(callback, 100);  //每 100 ms 呼叫 callback 一次




此例在進度條物件建立時 (create 事件) 設定在進度條上顯示進度的樣式, 然後將進度條數值控制變數 value 初始化為 0, 並設定一個計時器 timer 每 100 毫秒觸發呼叫 callback() 函數一次, 在此函數中會呼叫 Progressbar 的 value 方法以控制變數 value 值去更新進度條之數值然後增量 value 變數, 這個更新動作會觸發 change 事件去更新進度條內部 div 元素的內容, 當控制變數到達進度條的 max 設定值 (預設 100) 時呼叫 clearInterval() 停止計時器, 這動作會觸發 complete 事件, 此處是在 100% 後面添加 "(已完成)" 字樣.