顯示具有 jQuery UI 標籤的文章。 顯示所有文章
顯示具有 jQuery UI 標籤的文章。 顯示所有文章

2022年12月30日 星期五

jQuery UI 學習筆記 (十七) : 用下拉式選單做倒數日數計數器

今天是 2022 年最後一個上班日, 單位裡有兩位老同事 65 歲屆齡退休, 看到人家明年就可以睡到自然醒, 令我好生羨慕. 我要到 2031 年 6 月 30 才退, 還有 8 年半左右, 我到 GitHub 個人網站查看上回寫的退休倒數計日程式, 精確來說是 8 年又 183 天, 參考 : 


其實還有很多倒數計日的應用時機, 例如會考, 學測, ... 甚至是預期的平均壽命都可以. 因為很久沒寫 jQueryUI 了, 一時技癢就拿這個來練習一下吧! 將我的退休倒時記日器一般化, 可以選定截止日期, 計算離那個日期還有幾年幾天. 

最直覺的方式是用下拉式選單 SelectMenu, 年月日都設一個, 然後監聽 onchange 事件, 任何一個選擇器改變就立即進行倒數計算. 關於 SelectMenu 用法參考 :


如下面範例 1 所示 : 


測試 1 : 用 jQueryUI 的 SelectMenu 選取年月日以計算倒數日數 [看原始碼]

<!doctype html>
<html>
  <head>
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script> 
    <style>
      body {
        font-family: 微軟正黑體, Arial, Helvetica, sans-serif;
        font-size:12px;
        }
    </style>
  </head>
  <body>
    <div style="padding: 2px; margin: 3px;">
      <h3>倒數日數計算</h3>
      <p><b>請選擇截止日期 :</b></p>
      <select id="year">
        <option value="2023">2023 年</option>
        <option value="2024">2024 年</option>
        <option value="2025">2025 年</option>
        <option value="2026">2026 年</option>
        <option value="2027">2027 年</option>
        <option value="2028">2028 年</option>
        <option value="2029">2029 年</option>
        <option value="2030">2030 年</option>
        <option value="2031">2031 年</option>
        <option value="2032">2032 年</option>
        <option value="2033">2033 年</option>
        <option value="2034">2034 年</option>
        <option value="2035">2035 年</option>
        <option value="2036">2036 年</option>
        <option value="2037">2037 年</option>
        <option value="2038">2038 年</option>
        <option value="2039">2039 年</option>
        <option value="2040">2040 年</option>
        <option value="2041">2041 年</option>
        <option value="2042">2042 年</option>
        <option value="2043">2043 年</option>
        <option value="2044">2044 年</option>
        <option value="2045">2045 年</option>
        <option value="2046">2046 年</option>
        <option value="2047">2047 年</option>
        <option value="2048">2048 年</option>
        <option value="2049">2049 年</option>
        <option value="2050">2050 年</option>
      </select>
      <select id="month">
        <option value="Jan">1 月</option>
        <option value="Feb">2 月</option>
        <option value="Mar">3 月</option>
        <option value="Apr">4 月</option>
        <option value="May">5 月</option>
        <option value="Jun">6 月</option>
        <option value="Jul">7 月</option>
        <option value="Aug">8 月</option>
        <option value="Sep">9 月</option>
        <option value="Oct">10 月</option>
        <option value="Nov">11 月</option>
        <option value="Dec">12 月</option>
      </select>
      <select id="date">
        <option value="1">1 日</option>
        <option value="2">2 日</option>
        <option value="3">3 日</option>
        <option value="4">4 日</option>
        <option value="5">5 日</option>
        <option value="6">6 日</option>
        <option value="7">7 日</option>
        <option value="8">8 日</option>
        <option value="9">9 日</option>
        <option value="10">10 日</option>
        <option value="11">11 日</option>
        <option value="12">12 日</option>
        <option value="13">13 日</option>
        <option value="14">14 日</option>
        <option value="15">15 日</option>
        <option value="16">16 日</option>
        <option value="17">17 日</option>
        <option value="18">18 日</option>
        <option value="19">19 日</option>
        <option value="20">20 日</option>
        <option value="21">21 日</option>
        <option value="22">22 日</option>
        <option value="23">23 日</option>
        <option value="24">24 日</option>
        <option value="25">25 日</option>
        <option value="26">26 日</option>
        <option value="27">27 日</option>
        <option value="28">28 日</option>
        <option value="29">29 日</option>
        <option value="30">30 日</option>
        <option value="31">31 日</option>
      </select>
    </div>
    <div class="ui-state-highlight ui-corner-all" style="padding: 5px; margin: 5px; width:290px;">
      <span class="ui-icon ui-icon-info"></span>
      <span id="msg" style="font-weight: bold; "></span>
    </div>
    <input type='hidden' id='year_val' value='2023'>
    <input type='hidden' id='month_val' value='1'>
    <input type='hidden' id='date_val' value='1'>
    <script> 
      $(function(){
        function calculate(){
          var the_end=$("#month_val").val() + ' ' + 
                      $("#date_val").val() +  ', ' + 
                      $("#year_val").val();
          var t=Date.parse(the_end)-new Date().getTime();
          var total_days=Math.floor(t / (1000 * 60 * 60 * 24));
          var years=Math.floor(total_days / 365);
          var days=total_days % 365;
          var msg="離截止日期還有 " + years + " 年 " + days + " 天 (共 " + 
                  total_days + " 天)";
          $("#msg").text(msg);        
          }
        $("#year").selectmenu({width: 120});
        $("#month").selectmenu({width: 80});
        $("#date").selectmenu({width: 90});
        $('#year').on('selectmenuchange', function() {
          $("#year_val").val($(this).val());
          calculate();
          });
        $('#month').on('selectmenuchange', function() {
          $("#month_val").val($(this).val());
          calculate();
          });
        $('#date').on('selectmenuchange', function() {
          $("#date_val").val($(this).val());
          calculate();
          });
        calculate();   //初次仔入網頁時顯示初始值
        });
    </script>
  </body>
</html>

此例網頁中設置了三個隱藏元件 (type=hidden 的 input 元素), 分別用來儲存三個 SelectMenu 元件所選定之值, 每一個下拉式選單都有綁定 onchange 事件, 只要選項被改變就會更新相對應之隱藏元件之值, 這部分邏輯被寫成 calculate() 函式來處理. 下拉式選單的初始值就是第一個選項 (2023-01-01) 之值. 注意, SelectMenu 元件的寬度無法用 style 屬性設定 (無效), 必須在初始化時傳入 {width: } 物件來設定. 結果如下 : 




哈哈, 這正是我的退休倒數日數. 

下面改用 HTML5 的 Date 表單元件來選取截止日期, 用法參考下面這篇的範例 4 :


Date 元件可綁定 onchange 事件, 以便選定日期後觸發事件處理函式, 參考 :




<!doctype html>
<html>
  <head>
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
    <script> 
      function calculate(e){
        alert(e.target.value);
        }
    </script>
    <style>
      body {
        font-family: 微軟正黑體, Arial, Helvetica, sans-serif;
        font-size:12px;
        }
    </style>
  </head>
  <body>
    <div style="padding: 2px; margin: 3px;">
      <h3>倒數日數計算</h3>
      <p><b>請選擇截止日期 :</b></p>
      <input type="date" id="date" onchange="handler(event)"> 
    </div>
    <div class="ui-state-highlight ui-corner-all" style="padding: 5px; margin: 5px; width:290px;">
      <span class="ui-icon ui-icon-info"></span>
      <span id="msg" style="font-weight: bold; "></span>
    </div>
    <script>
      function handler(event){
        var YMD=event.target.value.split("-");   // [2022,12,31]
        var month=['Jan', 'Feb', 'Apr', 'Mar', 'May', 'Jun', 'Jul', 'Aug',
                   'Sep','Oct', 'Nov', 'Dec'];
        var the_end=month[parseInt(YMD[1])-1] + ' ' + YMD[2] +  ', ' + YMD[0];
        var t=Date.parse(the_end)-new Date().getTime();
        var total_days=Math.floor(t / (1000 * 60 * 60 * 24));
        var years=Math.floor(total_days / 365);
        var days=total_days % 365;
        var msg="離截止日期還有 " + years + " 年 " + days + " 天 (共 " + 
                total_days + " 天)";
        $("#msg").text(msg);      
        }
    </script>
  </body>
</html>

此例使用 HTML5 表單元件中的日期選擇器 (type=date 的 input 元件) 來選取截止日期, 注意, 此處所綁定的 onchange 事件, 呼叫端之傳入參數名稱一定要用 event, 亦即必須用 onchange="handler(event)",  用其他參數名稱會出現錯誤 (函式端則不受限, 可用 event 或 e 等等). 由於 Date 元件預設的日期格式為 YYYY-MM-DD, 所以要用 split() 將 Y, M, D 拆開, 其中 M 用陣列對照轉換成英文簡寫, 再與 Y, D 組成例如 'Dec 31, 2022' 的日期格式字串, 結果如下 : 





因為過了 12 點, 所以比上面範例 1 少一天啦. 

有空可以用 jQueryUI 本身的 datepicker 來做, 參考 : 


2022年12月28日 星期三

jQuery UI SPA 函式庫索引

這篇是 2020/8/22 整理的索引 (但忘了發布), 那時候將之前工作上所寫的 jQuery UI 單一網頁應用程式 (SPA) 做了一番整理, 因為以前為了能快速上工, 沒有時間完善架構, 只要測試能用就行, 隨著功能越加越多, 整個應用程式架構越來越混亂與擁腫, 所以趁此機會重構整個系統, 最重要的是留下紀錄, 免得時間一久自己也忘了為啥要這樣寫. 以下是這些紀錄的索引 :

# jQuery UI SPA 應用程式 (一) : 環境配置與程式架構
# jQuery UI SPA 應用程式 (二) : 動態表格 DataTables
# jQuery UI SPA 應用程式 (三) : 按鈕與對話盒
# jQuery UI SPA 應用程式 (四) : 檔案處理函式庫

最近打算用這些函式庫打造新的維運工具, 可能會常常查閱. 

~進行中~

2021年6月12日 星期六

GitHub 個人網站設計 (一) : 頁首 logo 與主架構

去年在 GitHub 上架設了個人網站 (只能靜態), 當時只是暫時用 jQuery UI 的手風琴結構寫了簡單的首頁就沒再繼續, 因為我主要是把 GitHub 當成是測試網頁的分享寄存空間而已, 參考 : 


最近幫湘雲老師架設 WordPress 網站時需要用 Javascript 做一些簡單的資料處理, 所寫的小程式打算整理起來放在網站中以便查找, 所以今天就花了點時間設計了一下個人網站的架構. 理工人的網站只要清爽樸素就好, 不需要太花俏 (實話是 : 缺乏藝術細胞).  

資料歸納整理適合使用頁籤 (tab) 結構, 我一直很喜歡 jQueryUI 的 hot-sneak 主題佈景, 所以就用此布景套在頁籤結構上作為首頁的版型, 當然上面還要再放個網站標誌圖檔, 基本上就是使用兩個 div 元素上下堆疊而成, 上面放 logo, 下面放 tab, 網頁碼如下 :

    <div style="text-align: center;">
      <img id="logo" src="images/logo.jpg">
    </div>
    <div id="tabs">
      <ul>
        <li><a href="home.htm">首頁</a></li>
        <li><a href="test.htm">網頁測試</a></li>
        <li><a href="tools.htm">小工具</a></li>
      </ul>
    </div> 

關於 jQueryUI 的頁籤參考 :


因為 tab 預設是佔滿整個頁面寬度 (頁籤靠左), 為了讓 logo 圖檔也能置中佔滿整個螢幕寬度, 所以將這個圖檔元素的 div 容器加上了 text-align: center 的樣式, 同時須給予一個 id 屬性, 用來根據 tab 頁籤來動態調整其寬度, 這就要用到 jQuery 物件的 width() 方法了, 此方法沒傳入參數為 getter, 會傳回物件之寬度, 有傳入參數時是 setter, 可設定元件之寬度, 控制程式碼如下 : 

    <script>
      $(function(){
        $("#tabs").tabs();
        $("#logo").width($("#tabs").width());
        });
    </script>

首先是呼叫 tab 物件的 tabs() 方法初始化頁籤結構, 然後呼叫其 width() 方法取得頁籤的寬度, 並將其傳入 logo 圖檔物件的 width() 方法來設定圖檔寬度. 

接下來只要製作 logo 圖檔再上傳到 GitHub 就可以了. 

我的構想是用一個狐狸頭像再加上網站名稱就好了, 首先於 Picpick 新增一個 1040x100 的空白圖片, 打上微軟正黑體字型大小為 36 的紫色網站名稱 "小狐狸事務所 の 網路實驗室", 然後外面套個方框 :




左邊的空白就是放狐狸頭像的地方, 我用 "fox png free" 搜尋谷歌找到下面這個免費圖檔網站 :


挑中其中這張狐狸圖樣 : 




下載後用 PicPick 開啟擷取其頭像並同比例縮小為高度 100px 的圖檔, 將其複製後貼到 logo 圖檔的左方空白區 : 




哈哈, 果然簡單又樸素. 

存檔為 logo.jpg 後先到 GitHub 個人網站根目錄下新增一個 images 子目錄 : 





然後將此 logo.jpg 圖檔上傳到 GitHub 個人網站的 images 子目錄下即可. 

最後修改原先的首頁檔 index.htm 如下 : 

<!DOCTYPE html>
<html>
  <head>
    <title>小狐狸事務所 の 網路實驗室</title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <style>
      body {font-family: Arial, Helvetica, sans-serif;}
      .ui-widget {font-size:90%;}
    </style>
  </head>
  <body>
    <div style="text-align: center;">
      <img id="logo" src="images/logo.jpg">
    </div>
    <div id="tabs">
      <ul>
        <li><a href="home.htm">首頁</a></li>
        <li><a href="test.htm">網頁測試</a></li>
        <li><a href="tools.htm">小工具</a></li>
      </ul>
    </div>
    <script>
      $(function(){
        $("#tabs").tabs();
        $("#logo").width($("#tabs").width());
        });
    </script>
  </body>
</html>

將此 index.htm 上傳覆蓋原來的檔案就大功告成啦! 成果如下 : 




在手機上瀏覽效果如下 : 




可見頁首圖檔的確會隨螢幕大小而變. 

其實也曾試用過 CSS3 新的寬度比例單位 vw, 也就是將 logo.jpg 的樣式設為 style="width: 100vw;", 這與以前的 100% 是類似效果, 但實測發現 100vw 會使圖檔右邊比頁籤多出一點, 調成 98vw 或 99vw 雖可改善, 但在手機上仍然會突出, 使頁面顯得不協調, 所以就不採用此方法了, vw 詳細用法參考 :  


網站目前只是空殼子, 有空再來慢慢整理. 

2020年10月29日 星期四

用 PHP 與 jQuery Ajax 存取資料庫 (習題)

前陣子網友詢問如何依據輸入的身分證從資料庫中提取有效日期且可進行修改, 參考下面這篇底下的留言 :

# 測試 jQuery 的 Ajax 函數 $.ajax()

因我這陣子在忙 jQuery Mobile 沒時間思考, 今天稍微告一段落, 就來做一下這道習題, 順便複習一下 jQuery UI 與 PHP, 久沒做還真的會生鏽.  此測試參考了之前的文章 :

# 

首先在 MySQL 建一個資料表 pid_valid_date, 根據網友問題描述, 需要兩個欄位 :

  • pid : varchar(10) 儲存身分證
  • valid_date : varchar(10) 儲存 YYYY-MM-DD 格式之有效日期

建資料表的 SQL 指令如下 :

--
-- 資料表結構 `pid_valid_date`
--

CREATE TABLE `pid_valid_date` (
  `pid` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL,
  `valid_date` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

建好後輸入如下測試資料,  SQL 指令為 :

--
-- 傾印資料表的資料 `pid_valid_date`
--

INSERT INTO `pid_valid_date` (`pid`, `valid_date`) VALUES
('A123456789', '2021-02-13'),
('Q123456789', '2025-11-21'),
('S123456789', '2023-05-29'),
('T123456789', '2020-12-31');



下面是只用 HTML5+jQuery 的範例 : 


測試 1 : 使用 HTML5 原生元件 [看原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="http://code.jquery.com/jquery-3.5.1.min.js"></script>
  </head>
  <body>
    <select id="pid" name="pid">
      <option value="">請選擇身分證號碼</option>
    </select>
    <input type="text" id="valid_date" name="valid_date">
    <button id="update">更新</button>
    <script>
      $(document).ready(function(){ 
        $.get({
          url: "http://tony1966.xyz/test/jquerytest/get_pid.php",
          dataType: "html",
          success: function(res) {
            $("#pid").append(res);
            }
          });
        $('#pid').on('change', function() {
          $.get({
            url: "http://tony1966.xyz/test/jquerytest/get_valid_date.php",
            dataType: "html",
            data: {pid: this.value},
            success: function(res) {
              $("#valid_date").val(res);
              }
            });
          });
        $("#update").on("click", function(e){
          $.get({
            url: "http://tony1966.xyz/test/jquerytest/update_valid_date.php",
            dataType: "text",
            data: {pid: $("#pid").val(), valid_date: $("#valid_date").val()},
            success: function(res) {alert(res);}
            });          
          });
        });
    </script>
  </body>
</html>

此例網頁中有三個元件 : 一個用來選擇身分證字號的下拉式選單, 一個用來顯示有效期限的單行文字欄位, 以及一個更新按鈕. 下拉式選單初始僅有提示用的文字選項, 身分證選項是透過 Ajax 向後端程式 get_pid.php 從資料庫取得, 此程式內容如下 : 

<?php
header('Content-Type: text/html;charset=UTF-8');
$host="mysql.hostinger.co.uk"; 
$username="u137801000_test"; 
$password="a123456"; 
$database="u137801000_test"; 
$conn=mysql_connect($host, $username, $password); 
mysql_query("SET NAMES 'utf8'"); 
mysql_select_db($database, $conn); 
$SQL="SELECT pid FROM `pid_valid_date`"; 
$result=mysql_query($SQL, $conn); 
$arr=array(); 
for ($i=0; $i < mysql_numrows($result); $i++) { 
     $row=mysql_fetch_array($result); 
     $option="<option value='".$row["pid"]."'>".$row["pid"]."</option>";
     $arr[$i]=$option; 
     } 
echo implode("\n", $arr);  
?>

此 PHP 程式會搜尋資料表 pid_valid_date 的 pid 欄位, 並在碟帶回圈中製作 option 元素組成的 HTML 回應字串, 此字串會在回應給前端網頁時傳入 append() 方法插入預設的 option 後面. 結果如下 : 



選取身分證字號會產生 change 事件並攜帶 pid 參數向後端程式 get_valid_date.php 提出 Ajax 請求, 此程式會搜尋 pid_valid_date 資料表中該 pid 的 valid_date 欄位值後傳回, 前端網頁收到回應後將其填入 valid_date 單行文字欄位中, 程式內容如下 :

<?php
header('Content-Type: text/html;charset=UTF-8');
$host="mysql.hostinger.co.uk"; 
$username="u137801000_test"; 
$password="a123456"; 
$database="u137801000_test"; 
$conn=mysql_connect($host, $username, $password); 
mysql_query("SET NAMES 'utf8'"); 
mysql_select_db($database, $conn); 
$SQL="SELECT * FROM `pid_valid_date` WHERE pid='".$_REQUEST["pid"]."'"; 
$result=mysql_query($SQL, $conn);  
$row=mysql_fetch_array($result); 
echo $row["valid_date"]; 
?>

使用者可修改 valid_date 後按更新鈕, 這會向後端程式 update_valid_date.php 提出 Ajax 請求 (攜帶 pid 與 valid_date 參數), 此程式會更新 pid 的 valid_date 欄位值, 成功傳回 OK, 失敗傳回 NG, 前端網頁收到回應後用 alert() 顯示結果, 此程式內容如下 : 

<?php
header('Content-Type: text/html;charset=UTF-8');
$host="mysql.hostinger.co.uk"; 
$username="u137801000_test"; 
$password="a123456"; 
$database="u137801000_test"; 
$conn=mysql_connect($host, $username, $password); 
mysql_query("SET NAMES 'utf8'"); 
mysql_select_db($database, $conn); 
$SQL="UPDATE `pid_valid_date` SET valid_date='".$_REQUEST["valid_date"]."' ".
     "WHERE pid='".$_REQUEST["pid"]."'"; 
$result=mysql_query($SQL, $conn);  
if (mysqli_error($conn)) {$msg="NG";}
else {$msg="OK";}
echo $msg; 
?>

測試 2 : 使用 jQueryUI 元件 [看原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="http://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <link href="http://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
    <style>
      body {font-family: Arial, Helvetica, sans-serif;}
      .ui-widget {font-size:80%;}
    </style>
  </head>
  <body>
    <select id="pid" name="pid">
      <option value="">請選擇身分證號碼</option>
    </select>
    <input type="text" id="valid_date" name="valid_date">
    <button id="update">更新</button>
    <script>
      $(document).ready(function(){        
        $("button").button();
        $("input").addClass("ui-widget ui-widget-content ui-corner-all");
        $("input").height($("button").innerHeight());
        $("#pid").selectmenu();
        $.get({
          url: "http://tony1966.xyz/test/jquerytest/get_pid.php",
          dataType: "html",
          success: function(res) {
            $("#pid").append(res);
            }
          });
        $('#pid').on('selectmenuchange', function() {
          $.get({
            url: "http://tony1966.xyz/test/jquerytest/get_valid_date.php",
            dataType: "html",
            data: {pid: this.value},
            success: function(res) {
              $("#valid_date").val(res);
              }
            });
          });
        $("#update").on("click", function(e){
          $.get({
            url: "http://tony1966.xyz/test/jquerytest/update_valid_date.php",
            dataType: "text",
            data: {pid: $("#pid").val(), valid_date: $("#valid_date").val()},
            success: function(res) {alert(res);}
            });          
          });
        });
    </script>
  </body>
</html>

此例使用 jQueryUI 來美化頁面,下拉式選單使用 selectmenu 元件, 單行文字欄位高度也經過調整與按鈕同高, 參考 : 


程式部分基本上與上面測試 1 雷同, 結果如下 :




將將, 完成啦! 




2020年9月18日 星期五

Javascript 函數傳回 return false 的問題

在 Javascrip/jQuery 的事件處理函數中常看到最後用 return false 結尾的用法, 常令人疑惑其用意是甚麼, 其實這是不要讓 HTML 元素執行其預設動作的方法, 例如超連結 a 元素的預設動作是將網頁導向 href 所指之位置; 而 form 元素的預設動作是提交表單 :
  • href="#" : 表示導向該網頁中的一個錨點 (anchor)
  • href="hello.htm" : 表示導向此網站的另一個網頁 hello.htm
  • href="http://www.foo.com/bar.htm" : 表示導向另一個網站之網頁
如果在 a 元素的 click 事件處理函數中最後傳回 false, 則 a 元素預設的連結導向動作會被取消, 例如下面範例中的兩個 a 元素都連結到本網頁之錨點 "#" :

  <a href="#" id="a1">a1</a>
  <a href="#" id="a2">a2</a>

其中的 id=a2 的超連結有特別掛上 click 事件處理器, 並且傳回 false, 而 id=a1 則沒有 : 

$("#a2").on("click", function(){
  return false;
  });

按 a1 超連結後網址列最後會多出一個 "#" 表示網頁會回到網頁的最上方, 但按 a2 超連結則不會, 參考 :


測試 1 : 超連結導向本網頁錨點 href="#" [看原始碼]

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>jQuery test</title>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
  <a href="#" id="a1">a1</a>
  <a href="#" id="a2">a2</a>
  <script>
    $(function(){
      $("#a2").on("click", function(){
        return false;
        });
      });    
  </script>
</body>
</html>

傳回 false 常見於將 a 元素當作按鈕用時, 當按下按鈕會執行事件處理函數, 如果不禁止其執行預設之網頁重導向動作, 事件處理函數執行完後網頁會回到網頁最上方 (href="#" 的預設動作), 造成網頁移動的不好觀感, 例如 : 


測試 2 : 超連結當作按鈕時使用 return false 停止預設動作 [看原始碼]

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>jQuery test</title>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
  <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
  <style>
    body {font-family: Arial, Helvetica, sans-serif;}
    .ui-widget {font-size:80%;}
  </style>
</head>
<body>
  <div style="height: 1000px;"></div>
  <a href="#" id="a1">a1</a>
  <a href="#" id="a2">a2</a>
  <script>
    $(function(){
      $("#a1").button();
      $("#a2").button();
      $("#a1").on("click", function(){
        alert("你按了 a1");
        });
      $("#a2").on("click", function(){
        alert("你按了 a2");
        return false;
        });
      });    
  </script>
</body>
</html>

此例中使用一個高度為 1000px 的 div 元素將按鈕推到網頁底下, 可見按 a1 按鈕後因為沒有垂回 false 導致執行 href="#" 的預設動作 (回到網頁最上方), 但按 a2 按鈕則網頁不會移動

但是在 "jQuery 應用程式設計極速上手" (Jay Blanchard, 上奇) 這本書裡的第 1-15 頁提到, 使用 return false 來停止預設動作可能會有問題, 因為 return false 實際上會先後呼叫事件物件 e 的e.preventDefault() 與 e.stopPropogation() 函數, 前者會停止預設動作, 後者會停止事件上升 (bubble up) 功能, 因此會把之後加入之超連結的 click 事件給阻擋掉, 使得預期的功能沒有出現.

比較妥當的做法應該是呼叫 preventDefault() 即可而不是 return false :

$("#a2").on("click", function(e){
   e.preventDefault();
  });

參考下面這篇文章, 作者清楚描述了 return false 的作用, 如果只是要停掉預設動作, 那就呼叫事件物件 e 的 preventDefault() 就好, 不要使用 return false : 


2020年9月12日 星期六

一個 jQuery UI 的 Web App 介面架構

我在一本 jQuery UI 的舊書 (2014) "jQuery 應用程式設計極速上手" (Jay Blanchard, 上奇), 此書原文版書名為 "Applied jQuery : develop and design".  在最後一章作者提出的一個 jQuery UI 為基礎的 Web App 架構, 它是一個單頁應用程式 (Single Page Application, SPA), 版面結構如下 :




上面的主導覽區作者使用精靈動畫 (sprite) 來製作圖片超連結; 次導覽區使用手風琴 (accordion, 摺疊選單), 右側則是透過 Ajax 方式載入之內容區.

作者曾為此書設立如下網站以便讀者可下載範例程式碼, 但現在已經關站了 :

# http://www.appliedjquery.com (無法連接)

於是我只好照書本內容逐一拼湊出原始程式樣貌 (但沒有處理上方主導覽區的精靈動畫, 因為我覺得有點複雜), 紀錄如下 :


測試 1 : jQuery UI 單頁應用程式 [看原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
    <style>
      body {font-family: Arial, Helvetica, sans-serif;
            height: 100%;
            margin: 0px auto;
            overflow-x: auto !important;
            overflow-y: hidden !important
            }
      .ui-widget {font-size:80%;}
      #mainNavBar {height: 75px;
                   padding: 0px 0px 0px 25px;
                   }
      #content1 {width: 20%;
                 height: 80%;
                 background-color: transparent;
                 vertical-align: bottom;
                 float: left;
                 margin: 5px 5px 0px 10px;
                 position: relative;
                 bottom: 0px;
                 }
      #contentArea1 {position: relative;
                     padding: 10px;
                     }
      #content2 {width: 77%;
                 height: 80%;
                 background-color: transparent;
                 vertical-align: top;
                 float: left;
                 margin: 5px 5px 0px 0px;
                 position: relative;
                 }
      #contentArea2 {position: relative;
                     padding: 10px;
                     overflow: auto;
                     }
      #footer {width: 99%;
               height: 75px;
               position: absolute;
               bottom: 0px;
               margin: 5px 5px 0px 5px;
               }
      #mainNavBar, content1, #content2, #footer {
               border: 1px dashed #ffff00;
               }
      #contentArea1, #contentArea2 {
               border: 1px dashed #00ff00;
               }
    </style>
  </head>
  <body>
    <!--上方主導覽列-->
    <div id="mainNavBar">

    </div>
    <!--左方次導覽列-->
    <div id="content1">
      <div id="contentArea1">
        <div id="accordion">
          <h2><a href="#">第 1 列標題</a></h2>
          <div>
            <ul style="padding: 0px; margin: 0px;">
              <li><a href="http://www.google.com.tw">Google</a></li>
              <li><a href="http://tw.yahoo.com">Yahoo</a></li>
            </ul>
          </div>
          <h2><a href="#">第 2 列標題</a></h2>
          <div>第 2 列內容</div>
          <h2><a href="#">第 3 列標題</a></h2>
          <div>第 3 列內容</div>
        </div>
      </div>
    </div>
    <!--右方主內容區-->
    <div id="content2">
      <div id="contentArea2">
        <div id="tabs">
          <ul>
            <li><a href="#tab1">頁籤 1</a></li>
            <li><a href="#tab2">頁籤 2</a></li>
            <li><a href="#tab3">頁籤 3</a></li>
            <li><a href="#tab4">頁籤 4</a></li>
          </ul>
          <div id="tab1">
            <p>這是頁籤 1</p>
          </div>
          <div id="tab2">
            <p>這是頁籤 2</p>
          </div>
          <div id="tab3">
            <p>這是頁籤 3</p>
          </div>
          <div id="tab4">
            <p>這是頁籤 4</p>
          </div>
        </div>
      </div>
    </div>
    <!--頁尾-->
    <div id="footer">
    </div>
    <script>
      $(function(){
        $(window).resize(function(){
          var windowHeight=$(window).height();
          $("#content1").height(windowHeight - 175 + "px");
          $("#contentArea1").height(windowHeight - 205 + "px");
          $("#content2").height(windowHeight - 175 + "px");
          $("#contentArea2").height(windowHeight - 205 + "px");
          });
        $("#accordion").accordion();
        $("#tabs").tabs();
        });
    </script>
  </body>
</html>

結果如下 :




看起來似乎還不錯, 但 Ajax 部分需要補強一下, 先記錄結果, 等有空再繼續. 以前在寫 EasyUICMS 時曾使用其 Layout 元件排版, 參考 :

# 用 jQuery EasyUI 打造輕量級 CMS (一)

但由於 jQuery UI 本身沒有這種元件, 必須透過 plug-in 外掛 UI Layout 支援才行, 參考 :

# http://layout.jquery-dev.net/
# jQuery佈局外掛UI Layout簡介及使用方法

2020年9月11日 星期五

jQuery UI 學習筆記 (十六) : 凸顯 (Hightlight) 與錯誤 (Error) 訊息

經過一個月來的努力, 終於來到 jQuery UI 元件測試的尾聲, 本篇測試的對象是用來在網頁中凸顯重要性或輸出錯誤訊息的 Highlight 與 Error 元件. 其 API 與教學文件參考 :

# https://jqueryui.com/height/
# http://api.jqueryui.com/height/
# https://jqueryui.com/error/
# http://api.jqueryui.com/error/

jQuery UI 參考書籍如下 :
  1. jQuery UI 使用者介面設計 (歐萊里, Studio Tib. 譯)
  2. jQuery UI 與 Plugin 開發實戰 (悅知文化, 吳哲穎譯)
  3. jQuery 全能權威指南 (上奇, 張亞飛)
  4. Pro jQuery 2.0 2nd ed. (Apress, Freeman Adam)
  5. jQuery UI in Action (Manning, TJ Vantoll)
  6. jQuery 應用程式設計極速上手 (上奇, 羅友志譯)
  7. 打造 jQuery 網頁風暴 (張子秋, 佳魁)
    主要參考書目為 No.5 的 jQuery UI in Action 這本.

    嚴格來說這兩個元件其實只是套用了 jQuery UI 特定樣式類別的 H1~H3, P, 或 DIV 等區塊式元素, 使用時並不需要呼叫物件方法加以初始化.

    Highlight 元件的的樣式類別為 "ui-state-highlight", 其外觀為黃底訊息框; 而 Error 元件之樣式類別為 "ui-state-error", 其外觀為紅底訊息框, 通常為了美觀都會再加上圓角樣式 "ui-corner-all", 例如 :


    測試 1 : 凸顯訊息 (highlight) 的效果 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <div class="ui-state-highlight ui-corner-all" style="padding: 5px; margin: 5px;">
          <p>
            <span class="ui-icon ui-icon-info"></span>
            <span style="font-weight: bold;">您的密碼將在 5 日後到期.</span>
          </p>
        </div>
        <h3 class="ui-state-highlight ui-corner-all" style="padding: 5px; margin: 5px;">
          <p>
            <span class="ui-icon ui-icon-info"></span>
            <span style="font-weight: bold;">您的密碼將在 5 日後到期.</span>
          </p>
        </h3>
        <p class="ui-state-highlight ui-corner-all" style="padding: 5px; margin: 5px;">
          <span class="ui-icon ui-icon-info"></span>
          <span style="font-weight: bold;">您的密碼將在 5 日後到期.</span>
        </p>
        <script>
          $(function(){
            });
        </script>
      </body>
    </html>

    此例中有三個凸顯訊息, 分別用 div, h1~h6, 以及 p 元素當容器, 只要為其套用 "ui-state-highlight ui-corner-all" 樣式類別, 即可將其改裝成圓角黃底外觀的訊息容器, 其內容通常會用兩個 span 元素包起來, 第一個 span 元素用來放置 icon 小圖示, 這只要套用 jQuery UI 內見的小圖示樣式類別即可, 例如 "ui-icon ui-icon-info" (i 圖示), 更多 icon 樣式類別參考 :

    # https://api.jqueryui.com/resources/icons-list.html

    訊息內容的第二個 span 元素則用來包覆文字訊息, 結果如下 :




    可見用 p 元素的訊息容器高度會比較貼近訊息高度.

    錯誤訊息類似凸顯訊息, 差別只是訊息容器套用 "ui-state-error ui-corner-all" 樣式類別, 而小圖示改為 "ui-icon ui-icon-alert" 樣式類別而已, 例如 :


    測試 2 : 錯誤訊息 (error) 的效果 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <div class="ui-state-error ui-corner-all" style="padding: 5px; margin: 5px;">
          <p>
            <span class="ui-icon ui-icon-alert"></span>
            <span style="font-weight: bold;">您輸入的帳號或密碼錯誤.</span>
          </p>
        </div>
        <h3 class="ui-state-error ui-corner-all" style="padding: 5px; margin: 5px;">
          <p>
            <span class="ui-icon ui-icon-alert"></span>
            <span style="font-weight: bold;">您輸入的帳號或密碼錯誤.</span>
          </p>
        </h3>
        <p class="ui-state-error ui-corner-all" style="padding: 5px; margin: 5px;">
          <span class="ui-icon ui-icon-alert"></span>
          <span style="font-weight: bold;">您輸入的帳號或密碼錯誤.</span>
        </p>
        <script>
          $(function(){
            });
        </script>
      </body>
    </html>

    結果如下 :




    當然也可以選擇其他的小圖示, 但 ! 圖示應該是蠻適合表示錯誤意涵的.

    到此終於把 jQuery UI 的全部元件用法都測完了, 大功告成, 收兵!

    # jQuery UI 學習筆記索引

    (這是第一個將全部主題寫完的學習筆記耶)

    2020年9月9日 星期三

    jQuery UI 學習筆記 (十五) : 工具提示 (Tooltips)

    最近暫停 R 語言的學習回頭整理 jQuery UI 筆記已近三周, 快到尾聲了加油! 本篇要測試的元件是工具提示 (Tooltip) 效果, 雖然在 jQuery UI 中這不算重要元件, 但鮮花也要配個好花瓶才能相得益彰不是嗎?

    Tooltip API 與教學文件參考 :

    # https://jqueryui.com/tooltip/
    # http://api.jqueryui.com/tooltip/

    jQuery UI 參考書籍如下 :
    1. jQuery UI 使用者介面設計 (歐萊里, Studio Tib. 譯)
    2. jQuery UI 與 Plugin 開發實戰 (悅知文化, 吳哲穎譯)
    3. jQuery 全能權威指南 (上奇, 張亞飛)
    4. Pro jQuery 2.0 2nd ed. (Apress, Freeman Adam)
    5. jQuery UI in Action (Manning, TJ Vantoll)
    6. jQuery 應用程式設計極速上手 (上奇, 羅友志譯)
    7. 打造 jQuery 網頁風暴 (張子秋, 佳魁)
    主要參考書目為 No.5 的 jQuery UI in Action 這本.

    工具提示是 HTML 元素的 title 屬性所提供的功能, 當滑鼠移動到元素上 (hover) 時就會出現一個方框顯示訊息, 這對表單輸入非常有用, 可提醒使用者如何填寫, 但原始 HTML 的 title 提示功能有下列缺點 :
    1. 外觀與顯示時間, 時長以及位置無法控制.
    2. 顯示內容只能是純文字, 無法使用 HTML, 且顯示效果隨瀏覽器而異.
    例如 :


    測試 1 : 原始的 HTML 元素 title 屬性提示效果 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="account">帳號</label>
        <input type="text" id="account" title="請輸入帳號"><br>
        <label for="password">密碼</label>
        <input type="password" id="password" title="請輸入密碼(英數字)">
        <button title="提交">登入</button>
        <script>
          $(function(){
            $("button").button();
            });
        </script>
      </body>
    </html>

    結果如下 :




    可見帶 title 屬性的 input 與 button 元素, 其提示訊息就是一個非常陽春的方框. 但若取得這些有 title 屬性元件的 jQuery 物件後呼叫 tooltip() 方法則可美化工具提示框, 並且有跨瀏覽器一致的視覺效果 :

    $("input").tooltip();
    $("buttont").tooltip();

    或者用 document 取得 HTML 文件內的全部元素之 jQuery 物件集合, 這樣全部具有 title 屬性之元素都會套用工具提示效果 :

    $(document).tooltip();

    例如 :


    測試 2 : 呼叫 tooltip() 初始化工具提示效果 : 提示內容寫在 title 屬性中 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="account">帳號</label>
        <input type="text" id="account" title="請輸入帳號"><br>
        <label for="password">密碼</label>
        <input type="password" id="password" title="請輸入密碼(英數字)">
        <button title="提交">登入</button>
        <script>
          $(function(){
            $("button").button();
            $('input').addClass("ui-widget ui-widget-content ui-corner-all");
            $('input').height($("button").innerHeight());
            $(document).tooltip();
            });
        </script>
      </body>
    </html>

    結果如下 :




    可見當滑鼠移到每一個含有 title 屬性的元素時都會跳出具有陰影的美美提示了.

    "jQuery UI in Action" 這本書裡提到即使是在呼叫 tooltip() 後才加入的元素仍然有效, 例如 :


    測試 3 : 呼叫 tooltip() 初始化後再動態加入之元素仍然有效 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <script>
          $(function(){
            $(document).tooltip();
            $('body').html("<input type='text' title='帳號'><br>");
            $('body').append("<input type='text' title='密碼'>");
            });
        </script>
      </body>
    </html>

    此例網頁中 body 內原本並無任何表單元素, 我們是在呼叫了 tooltip() 之後再呼叫 html() 與 append() 方法添加兩個 text input, 結果如下 :



    可見在呼叫 tooltip() 後才動態加入 DOM 樹狀結構中的元素仍然會套用 Tootip 效果.

    jQuery UI 的工具提示元件提供了許多選項屬性可用來設定 tooltip 之功能, 其中比較重要的是 content 與 position, 分別用來設定提示內容與出現之位置.

    在提示內容不一定要預先寫在元素的 title 屬性中, 可以在呼叫 tooltip() 初始化元素之工具提示功能時傳入含有 content 屬性之選項物件去設定, 其值可以是字串或函數, 此函數要 return 提示訊息字串 :

    obj.tooltip({content: "提示訊息"});
    obj.tooltip({content: function(){return "提示訊息"}});

    例如 :


    測試 4 : 呼叫 tooltip() 初始化工具提示效果 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="account">帳號</label>
        <input type="text" id="account" title=""><br>
        <label for="password">密碼</label>
        <input type="password" id="password" title="">
        <script>
          $(function(){
            $("#account").tooltip({content: "<b>請輸入帳號</b>"});
            $("#password").tooltip({
              content: function() {return "<i>請輸入密碼(英數字)</i>";}     
              });
            });
        </script>
      </body>
    </html>

    此例中兩個 text input 元素的工具提示訊息並非事先寫在 title 屬性中, 而是在呼叫 tooltip() 進行初始化時以 content 選項設定, 第一個 text input 的 content 屬性直接用字串, 第二個則用函數傳回字串, 這個做法的好處是可使用 HTML 語法來呈現提示內容, 因為在 title 屬性中無法使用 HTML 標籤, 結果如下 :




    可見 content 中的粗體元素 b 與斜體元素 i 都顯現效果於提示訊息中. 注意, 雖然提示訊息改在 content 中設定, 但是 title 屬性還是必須存在, 因為 tooltip() 的作用對向必須具有 title 屬性, 只要賦予空值即可.

    除了在初始化時用選項物件設定外, 也可以在初始化後用 option 方法來設定 content 屬性 :

    obj.tootip("option", "content", "提示訊息")
    obj.tootip("option", "content", "提示訊息")


    測試 5 : 初始化後用 option 方法設定 content 屬性 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="account">帳號</label>
        <input type="text" id="account" title=""><br>
        <label for="password">密碼</label>
        <input type="password" id="password" title="">
        <script>
          $(function(){
            $("#account").tooltip();       //一定要先初始化
            $("#password").tooltip();     //一定要先初始化
            $("#account").tooltip("option", "content", "<b>請輸入帳號</b>");
            $("#password").tooltip("option", "content", "<i>請輸入密碼(英數字)</i>");
            });
        </script>
      </body>
    </html>

    此例先呼叫 tooltip() 初始化後再呼叫 option 方法去設定 content 屬性, 結果與上面範例 4 一樣. 注意, 一定要先做初始化才能呼叫 option 方法, 否則會出現物件不存在之錯誤訊息. 同樣地, 表單元素中也一定要有 title 屬性.

    工具提示元件預設會套用到具有 title 屬性的元素上, 但這可以在初始化時用 items 選項來設定, 例如 id 屬性可用 [id], 另外圖片的提示是放在 alt 屬性上則指定為 img[alt], 如果要指定到任何元素則用 * :

    obj.tooltip({itmes: "[id]"});         //將提示套用到有 id 屬性的元素上
    obj.tooltip({itmes: "img[alt]"});  //將提示套用到有 alt 屬性的 img 元素上
    obj.tooltip({itmes: "*"});             //將提示套用到所有元素上

    也可以在初始化後利用 option 方法設定 items 選項 :

    obj.tootip();
    obj.tootip("option", "items", "[id]");

    例如 :

    測試 6 : 初始將工具提示套用到所有元素上 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="account">帳號</label>
        <input type="text" id="account"><br>
        <label for="password">密碼</label>
        <input type="password" id="password">
        <script>
          $(function(){
            $("#account").tooltip({
              content: function() {return this.id},
              items: "[id]" 
              });
            $("#password").tooltip({
              content: "<i>請輸入密碼(英數字)</i>",
              items: "*" 
              });
            });
        </script>
      </body>
    </html>

    此例中兩個 input 元素並無 title 屬性, 但透過初始化時以 items 屬性指定套用的對象, 前者為套用到有 id 屬性者 (items: "[id]"), 後者為套用到任何元素 (items: "*"), 這就更改了預設對象為具有 title 屬性者, 因此仍能正常顯示工具提示訊息, 如果少了 items 選項就不會顯示了, 結果如下 :



    由於 id=account 的 input 元素其提示訊息為透過函數傳回本身 id, 故提示訊息為 account.

    jQuery UI 學習筆記 (十四) : 文字輸入框的主題樣式

    最近在測試 jQuery 時發現 jQuery UI 對大部分表單元素都有進行外觀美化, 例如呼叫 button() 可將原本很陽春的 HTML 按鈕改裝成有主題佈景的美美按鈕, 唯獨文字輸入元素 text input 與 textarea 沒有, 顯得與其他美美的表單元素格格不入, 例如下面這個原始的 HTML 網頁 :


    測試 1 : 原始的 HTML 文字輸入元素效果 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="memo">備註</label>
        <textarea id="memo" rows="4" cols="28"></textarea><br>
        <label for="category">類別</label>
        <input type="text" id="category">
        <button title="儲存">儲存</button>
        <script>
          $(function(){
            $("button").button();
            });
        </script>
      </body>
    </html>

    此例的 text input 與 textarea 仍為 HTML 原始外觀, 不像按鈕可呼叫 button() 方法套用主題樣式, 在視覺上不甚搭配 :




    解決辦法可參考下列文章 :

    # jQuery UI styled text input box

    其中第 18 個回覆的做法我覺得最適當, 就是幫 input 與 textarea 加上 jQuery 物件之 ui-widget 相關樣式類別 :

    $('input, textarea').addClass("ui-widget ui-widget-content ui-corner-all");

    例如 :


    測試 2 : 套用 ui-widget 相關樣式類別之效果 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="memo">備註</label>
        <textarea id="memo" rows="4" cols="28"></textarea><br>
        <label for="category">類別</label>
        <input type="text" id="category">
        <button title="儲存">儲存</button>
        <script>
          $(function(){
            $("button").button();
            $('input, textarea').addClass("ui-widget ui-widget-content ui-corner-all");
            });
        </script>
      </body>
    </html>

    結果如下 :




    可見 text input 與 textarea 元素外觀變美了, 邊框不僅變成圓角, 且套用了佈景主題樣式.

    不過還有一個缺點 : text input 的高度似乎太小, 與按鈕的高度不協調, 這可以透過 height() 方法來設定, 例如 :


    測試 3 : 設定 text input 元素高度與按鈕同高 [看原始碼]


    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="memo">備註</label>
        <textarea id="memo" rows="4" cols="28"></textarea><br>
        <label for="category">類別</label>
        <input type="text" id="category">
        <button title="儲存">儲存</button>
        <script>
          $(function(){
            $("button").button();
            $('input, textarea').addClass("ui-widget ui-widget-content ui-corner-all");
            $('input').height($("button").innerHeight());
            });
        </script>
      </body>
    </html>

    此例先呼叫 button 元素物件之 innerHeight() 取得元素本身 (內) 高度, 傳回值為高度 px 數值, 然後將其傳給 text input 元素物件之 height() 方法設定高度, 結果如下 :




    這樣看起來就搭調多了. 最後我們為範例 3 加上主題布景選擇器 :


    測試 3 : 外觀隨主題佈景切換之文字輸入框 [看原始碼]

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <meta charset="utf-8">
        <meta http-equiv="cache-control" content="no-cache">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <link id="theme" href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
        <style>
          body {font-family: Arial, Helvetica, sans-serif;}
          .ui-widget {font-size:80%;}
        </style>
      </head>
      <body>
        <label for="themes">布景</label>
        <!-- 主題佈景選擇器 -->
        <select id="themes">
          <option value="base">base</option>
          <option value="black-tie">black-tie</option>
          <option value="blitzer">blitzer</option>
          <option value="cupertino">cupertino</option>
          <option value="dark-hive">dark-hive</option>
          <option value="dot-luv">dot-luv</option>
          <option value="eggplant">eggplant</option>
          <option value="excite-bike">excite-bike</option>
          <option value="flick">flick</option>
          <option value="hot-sneaks">hot-sneaks</option>
          <option value="humanity">humanity</option>
          <option value="le-frog">le-frog</option>
          <option value="mint-choc">mint-choc</option>
          <option value="overcast">overcast</option>
          <option value="pepper-grinder">pepper-grinder</option>
          <option value="redmond">redmond</option>
          <option value="smoothness">smoothness</option>
          <option value="south-street">south-street</option>
          <option value="start">start</option>
          <option value="sunny">sunny</option>
          <option value="swanky-purse">swanky-purse</option>
          <option value="trontastic">trontastic</option>
          <option value="ui-darkness">ui-darkness</option>
          <option value="ui-lightness">ui-lightness</option>
          <option value="vader">vader</option>
        </select>
        <script>
          $(function(){
            $("#themes").selectmenu();
            $("#themes").val("hot-sneaks");
            $("#themes").selectmenu("refresh");
            $('#themes').on('selectmenuchange', function() {
              var theme=$(this).val();
              var href="https://code.jquery.com/ui/1.12.1/themes/" + theme +
                       "/jquery-ui.min.css";
              $("#theme").attr("href", href);
              });
            }); 
        </script>
        <br><br>
        <label for="memo">備註</label>
        <textarea id="memo" rows="4" cols="28"></textarea><br>
        <label for="category">類別</label>
        <input type="text" id="category">
        <button title="儲存">儲存</button>
        <script>
          $(function(){
            $("button").button();
            $('input, textarea').addClass("ui-widget ui-widget-content ui-corner-all");
            $('input').height($("button").innerHeight());
            });
        </script>
      </body>
    </html>

    此例利用選擇器切換主題佈景觀察文字輸入框外框是否隨之改變, 結果如下 :




    可見這樣的設定確實可讓 text input 與 textarea 華麗轉身.

    以上範例全部放在 GitHub 個人網頁空間, 拿 GitHub 當靜態網頁伺服器真的好棒棒耶.