2013年5月29日 星期三

搞定

這幾天忙著為 PHP 架站機補上最後一塊拼圖-檔案上傳, 今晚終於搞定啦. 雖然有幾個受歡迎的 plugins 外掛可用, 但為了親自體會自製的樂趣, 同時保持 jQuery UI 主題佈景的一致性, 我還是手工打造, 用了一個從網路上學來的技巧, 終於~哈哈哈, 搞定啦.
月底會比較忙, 明天起要衝公司的專案, 所以沒空做總結. 六月初再來記心得.

2013年5月25日 星期六

關於語言干擾問題

最近幾天在寫 PHP 架站機程式時, 常出現 undefined token 的錯誤, 再三檢查都覺得 OK 呀, 語法沒錯ㄚ, 再仔細一看發現, 呵呵, 這是前端 Javascript 的世界, 我怎麼用點號來連接字串呢? 再來第二個常見錯誤, 就是在 jQuery 中使用了 $ 開頭的變數名稱, 因為我把它當作 PHP 來寫, 難怪會相衝. 這就是機器語言世界裡的 "語言干擾現象".
以前在研究所念語言學的時候, 有探討過語言干擾現象, 當時正好是小狐狸們牙牙學語期, 剛開始我觀察到她們在母語與國語之間似乎可以自由切換, 跟阿公阿嬤講客家話; 到幼稚園跟同學講國語, 所以我認為, 多語系社會裡, 語言干擾的憂慮是多餘的, 就像書上說瑞士小孩從小接觸義, 德, 法三國語言, 不會有干擾問題, 該說哪一種語言就說哪一種. 不過現在因為母語講得少了, 有時菁菁打電話給鄉下阿嬤時, 忘記客語怎麼說時就用國語, 甚至用英文哩, 但我覺得是因為母語退化所呈現的替代關係, 不是語言干擾現象. 如果你擅長這兩種語言, 事實上是可以切換自如的.
但是電腦語言似乎就有點不同了, 它不像自然語言那樣有說話的對象, 大腦會潛意識自動切換, 從編輯器看到的都是長得很像的程式碼, 除非有特別注意, 要不然很容易就發生干擾現象, 常常寫完後端 PHP 回到前端寫 Javascript 或 jQuery, 會走不出來, 還是用點號來連接字串, 用 $ 做變數開頭.
這就是以前剛學 ASP 時, 我選擇 Javascript 而不是大家常用的 VBscript 來寫後端程式的理由, 因為這樣我只要學一種語言就可以前後通吃, 一招走江湖啦. 可惜 ASP 後來變成 ASP.NET, 對於擁抱 Java 陣營的我而言, 實在不願意再學一種新語言, 到現在在公司還是繼續用 ASP 技術. 直到遇到 cURL, 才下定決心, 再學一種後端語言 PHP. 所幸 PHP 基本語法跟 Javascript 大同小異, 很容易學, 就是變數都要以 $ 開頭, 有點小困擾就是了.
唉, 幹嘛弄出這麼多語言呢? 難怪學資工的永遠學不完. 昨天在圖書館看到一本 JVM 的書, 裡面回顧了 Java 各版本蛻變的歷史, 陸續加入了泛型什麼的, 卡好, 考 SCJP 時讀過呀, 現在沒用到早已經忘光光. 學了也從來沒用到這些東東. 或許搞大型專案的, 搞軟體工程的會用到吧. 我只要程式能用就行, 達成目的最重要, 不要學那麼多語言, 兩三樣就好. 至於實做技巧, 嗯, 樸實直觀, 以後自己看得懂就行. 人生要做的事還很多, 沒那麼多時間花在鑽研這些高級技術上.

2013年5月21日 星期二

關於麻瘋病

晚上二哥上完英文課回來, 一邊看雜誌就問我, 痲瘋病是怎麼傳染的? 我說這好像是細菌感染造成的, 應該是接觸吧? 但記得上回看韓劇醫道時, 許浚跟隨三積大師照顧痲瘋病人, 似乎傳達一個印象, 好像他們都不怕被傳染, 難道它不是傳染病?
馬上查了一下維基, 原來這是由痲瘋桿菌傳染導致的, 主要傳染途徑是上呼吸道感染 (這不是與感冒一樣嗎?). 小孩較容易被感染, 成人較不會, 可能是免疫力較強吧. 驚人的是, 潛伏期有時長達 40 年! 但這病現在是可以用抗生素治癒的.

參考 :
https://zh.wikipedia.org/wiki/%E9%BA%BB%E9%A3%8E%E7%97%85

2013年5月20日 星期一

jQuery 外掛 dataTables 的表格欄位排序問題

這幾天在寫架站機時發現, 訪客紀錄竟然沒有照 ajax 傳回的以日期時間倒序排列 (最近到訪者在最上面), 反而是順序排列, 原先以為欄位不該用 datetime, 應該用字串 varchar(255), 試了老半天, 結果無效.
晚上搜尋了一下, 發現問題出在 aaSorting 這個選項上, 我在寫產出程式碼的 get_datatable() 函式時根本不知道要設定這選項, 所以就被默認為用預設值, 它的預設值是 :

"aaSorting": [[0,'asc']]

意思是以第一個欄位 (索引 0) 升序排列, 難怪即使後端 ajax 用 ORDER BY visit_time DESC 傳回倒排的記錄, 到了 dataTables 物件手裡, 又被以升序再排一次. 這也衍生一個問題, 這樣排序兩次不是會讓回應時間拉長嗎? 要怎麼取消預設排序動作呢? 只要設一個空陣列給它即可, 一維就可以了 :

"aaSorting": []

修改了 jqueryui.php 函式庫的 get_datatable() 函式, 加上這個取消排序的設定, 果然就搞定了. 這個問題讓我覺得, 還是要遇到問題後, 經過想方設法去解決, 你才會真正了解一個工具的妙用ㄚ.
其實 aaSorting 選項還可以設定各欄的排序方向, 例如 :

"aaSorting": [[0,'asc'], [2, 'desc']]

表示先以第一欄位升序排列, 再以第三欄位倒敘排列. 但因為我習慣在後端直接以 SQL 指令的 ORDER BY 就先排序好, 所以就沒再打算把 sorting 方向寫進 get_datatable() 函式裡去 : 一律取消預設排序最單純啦.

2013年5月19日 星期日

如何套用 jQuery UI 頁籤 tabs 的樣式

我用 jQuery UI tabs 小工具作為網頁內容的容器, 內容會用一個 fieldset 元素包起來, 我希望當改變布景主題時, 這個 fieldset 的邊框顏色也能配合改變, 也就是說它的 border-color 樣式要能夠套用 jQuery UI 布景的設定, 這該怎麼做呢?
早上花了很多時間搜尋, 但是一無所獲. 後來用 Crome 的 Javascript 控制台工具查看 DOM 內容, 發現這其實很簡單, 你去看作為 tabs 容器的 div 元素, 在呼叫 tabs() 方法後, jQuery UI 會將此 div 元素加上一堆 class :

<div id="tabs" class="ui-tabs ui-widget ui-widget-content ui-corner-all">...</div>

我的 fieldset 就是放在 div 的內容裡. 要讓 fieldset 套用 tabs 的邊框顏色, 關鍵就是 ui-widget-content 這個樣式類別, 查看此類別內容如下 (這是 hot-sneaks 主題的設定值) :


.ui-widget-content {
border: 1px solid #aaaaaa;
background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;
color: #2c4359;
}


所以 fieldset 只要套用 ui-widget-content 類別就可以了 :

<fieldset class="ui-widget-content">
我的內容
</fieldset>

這樣不論主題背景改成哪一種, fieldset 的邊框顏色也會跟著一起改變, 可以讓網頁有整體感, 不會很突兀.

2013年5月12日 星期日

鳥蛋怎麼孵

今天母親節, 菁菁跟水某去清水里外婆那裡, 下午回來時帶回一顆鳥蛋, 說是外婆整理果樹時發現, 她要帶回來養, 我說那孵不出來啦, 但是充滿母性的她不聽, 偏要我弄個燈泡來孵. 她還用毛線球覆蓋, 放在檯燈下孵, 這 ... 有效嗎?
晚上回到高雄, 我就找了一下網路, 輸入 "鳥蛋怎麼孵", 就出現一大堆資料, 不看還好, 看了真是會昏倒. 其中一個是這樣 : (Yahoo 知識)

"先準備一個鍋子, 把開水倒進去, 煮開之後放一些火鍋料, 之後就可以把你的鳥蛋放進去孵了, 孵完之後看要加沙茶醬或不加都很好吃."

這是來亂的嗎? 還有一個 :

"鳥蛋怎麼孵~ 準備兩個碗公...蛋白跟蛋黃分開...用蛋白看你要敷臉還是敷哪..."

他是故意聽不懂的嗎?

這一篇科展的寫的很詳細, 就是要用燈泡來孵啦, 我已答應菁菁明天要去小北買燈泡.

2013年5月11日 星期六

產生 jQuery UI DataTables 表格套件的 PHP 程式

測試完 DataTables 套件後 ("jQuery 套件 DataTables 的測試"), 雖然搞清楚了那些複雜選項的用法, 但為了能在 PHP 專案中快速搞定表格呈現, 我把它的常用設定寫成了 PHP 函式, 這樣以後只要簡單呼叫就能做出一個 DataTables 表格了. 此函式是針對表格資料來源為 Ajax JSON 而設的, 因為我們最常從後端資料庫擷取內容後, 在前端以表格呈現. 而對於資料來源為網頁本身者, 既然要在網頁上寫內容了, 那就連 jQuery 程式全部在前端寫吧, 不需要彆扭地用 PHP 來產出啊.
此函式主要的功能如下 :
  1. 預設不分頁, 但以 400px 的高度設定垂直捲軸, 資料長度不足時, 高度設定要自動瓦解.
  2. 分頁時預設是右下角為全套 (full_numbers) 按鈕, 右上角選單多一個 "全部"
  3. jQuery UI 預設不套用
  4. 預設語言為繁體中文
其呼叫介面如下 :

function get_datatable($id,
                                  $url,
                                  $column [,
                                $scrollY="400px" [,
                                  $paginate=false [,
                                $page_buttons="" [,
                                $jqueryui=false [,
                                  $locale="zh-TW"]]]]])

此函式有三個必要參數, 五個選項參數, 各參數說明如下 :

$id                 : 字串, table 元素之 id                             
$url                : 字串, Ajax 後端資料提供程式 url
$column         : 二維陣列, 表格欄位標頭 (設定 aoColumns 選項).
                        第一維乃關聯式陣列, 有四個索引 :
                       $column["title"]:"名稱"                   欄位名稱 (必須)
                       $column["width"]:"20px"/"20%"      欄位寬度 (非必須)
                       $column["class"]:"editClass"           樣式類別 (非必須)
                       $column["type"] :"string"/"numeric"  排序模式 (非必須, 預設 string)
$scrollY          : 字串, 指定垂直卷軸高度, 預設為 "400px", 格式為 CSS 高度.
                        設為 "50%" 表示捲軸高度為內容一半,
                         設為 "100%" 顯示全部內容, 捲軸消失.
$page_buttons : 字串, 分頁時設定右下角分頁按鈕類型, 預設 "full" :
                         "two"  : 上頁/下頁兩個按鈕 (即 two_button)
                         "full"    : 上頁/下頁/首頁/尾頁/鄰近5頁按鈕  (即 full_numbers)
$jqueryui          : true/false, 是否套用 jQueryUI 主題佈景, 預設 false
$locale             : 字串, 語言設定, 預設 "zh-TW", 若要英文介面則傳入 ""


這樣只要至少指定三個參數 : table 元素 id, 欄位表頭陣列, 以及提供資料的後端程式就行了, 預設是一個不分頁, 具有 400px 高度垂直捲軸的表格. 注意,  欄位表頭陣列 $columns 最起碼必須要有索引為 title 的元素 $column["title"] 即可, 其他 width/class/type 索引視需要而設, 例如 :

$url="get_stocks_list.php";
$column["title"]=array("編輯","股票名稱","股票代號");
$column["width"]=array("20px","20%","");
$column["class"]=array("editClass","","");
$column["type"]=array("","string","numeric");
echo get_datatable("table1", $url, $column); //不分頁, 有垂直捲軸 (400px)

其他呼叫範例如下 :

echo get_datatable("table1", $url, $column, "100%"); //不分頁, 列出全部資料
echo get_datatable("table1", $url, $column, "600px"); //不分頁, 有垂直捲軸
echo get_datatable("table1", $url, $column, "", true); //分頁 (全套按鈕)
echo get_datatable("table1", $url, $column, "", true, "two"); //分頁 (上下頁按鈕)
echo get_datatable("table1", $url, $column, "", true, "", true); //全套按鈕, 套用 jQuery UI
echo get_datatable("table1", $url, $column, "", true, "", true, ""); //上下頁按鈕, 套用 jQuery UI

接下來我們就延續上一篇文章 "jQuery 套件 DataTables 的測試" 的範例 21, 用我們這個 PHP 函式來產出相同的效果. 我們把範例  21 的 datatable_21.htm 修改為 datatable_22.php, 首先要匯入含有 get_datatable() 函式的函式庫 :


<?php
include_once("../lib/jqueryui.php");
?>

然後拿掉 table 元素與相關的 script, 改成 PHP 來輸出同樣的 jQuery 指令 :


<?php
$url="get_stocks_list_8.php";
$column["title"]=array("編輯","股票名稱","股票代號");
$column["width"]=array("20px","20%","");
$column["class"]=array("editClass","","");
$column["type"]=array("","string","numeric");
echo get_datatable("table1", $url, $column, "", true, "", true);  //分頁, jQueryUI, 全按鈕
?>

另外, 後端程式部分,  點某一列就開啟該股票的 Yahoo 股市今日行情畫面功能要改用超連結來實現 (因為我們的 PHP 函式功能固定了, 沒辦法再去讀取列). 只要把範例 21 的後端供檔程式 get_stocks_list_7.php 修改成如下的 get_stocks_list_8.php, 給 stock_id 加上 Yahoo 股市今日行情超連結就行了 :

header('Content-Type: text/html;charset=UTF-8');
$host="mysql.1freehosting.com"; //MySQL 主機位址
$username="tony1966_test"; //MySQL 使用者名稱
$password="123456"; //MySQL 使用者密碼
$database="testdb"; //資料庫名稱
$conn=mysql_connect($host, $username, $password); //建立連線
mysql_query("SET NAMES 'utf8'"); //設定查詢所用之字元集為 utf-8
mysql_select_db($database, $conn); //開啟資料庫
$SQL="SELECT * FROM `stocks_list`";
$result=mysql_query($SQL, $conn); //執行 SQL 指令

$stock=array();
for ($i=0; $i<mysql_numrows($result); $i++) { //走訪紀錄集 (列)
     $row=mysql_fetch_array($result); //取得列陣列
     $stock_name=$row["stock_name"];
     $stock_id="<a href='http://tw.stock.yahoo.com/q/q?s=".
                      $row["stock_id"]."' target='_blank'>".$row["stock_id"]."</a>";
     $edit="<a href='edit_stocks_list.php?stock_id=".$row["stock_id"]."&stock_name=".
               $row["stock_name"]."' target='_blank'><img src='edit.gif' ".
               "style='border-width:0px;width:15px;height:15px;'></a>";
     $stock[$i]=array($edit, $stock_name, $stock_id);
     } //end of for
$arr["aaData"]=$stock;
echo json_encode($arr);  //將陣列轉成 JSON 資料格式傳回

測試範例 22 : http://mybidrobot.allalla.com/jquerytest/datatable_22.php [看原始碼]


結果是不是與範例 21 一樣? (因 CSS 樣式檔已改為  jquery.dataTables_themeroller.css 了, 故外觀有一點點不同). 不過我發現一個問題, 當左上角的每頁筆數選單改為不是 10 時, 表格內容會向右凸出約 10px, 看來有點突兀, 但這不是 PHP 產出的問題, 在上一篇文章 "jQuery 套件 DataTables 的測試" 的範例 16 就出現了. Why?  
接下來看看不分頁範例. 下列範例 23 則是不分頁有垂直捲軸的表格 :


<?php
$url="get_stocks_list_8.php";
$column["title"]=array("編輯","股票名稱","股票代號");
$column["width"]=array("20px","20%","");
$column["class"]=array("editClass","","");
$column["type"]=array("","string","numeric");
echo get_datatable("table1", $url, $column, "400px", false, "", true); //不分頁, jQuery UI
?>

測試範例 23 : http://mybidrobot.allalla.com/jquerytest/datatable_23.php [看原始碼]

本週忙 DataTables 測試終於可以告一個段落了, 雖是半路殺出程咬金吸引了我的注意, 但也解決了我在 jQuery 專案設計上的大問題. 相信可以簡化與加速將來的專案開發.

2013年5月6日 星期一

jQuery 套件 DataTables 的測試

ExtJS 框架以其起家的 DataGrid 元件聞名, 而 jQuery 框架雖然沒有內建類似 DataGrid 的功能, 但也有 dataTables 套件可用. 其實這是產品設計策略的差異, ExtJS 是一次到位, 提供全方位解決方案 (但是比較龐大, 學習曲線陡峭); 而 jQuery 則是保持一個精簡快捷的核心, 應用功能則盡量用 plugin 來實現, 所以是百花齊放. 以下先就 dataTables 這個套件的使用方式作簡要說明後, 再進行功能測試.

dataTables 是蘇格蘭 SpryMedia 工作室的 Mr.Allan Jardine 之作品, 可以結合 jQuery UI 的主題佈景, 在網頁上為資料表格呈現豐富的功能, 例如搜尋, 排序, 以及透過 Ajax 動態擷取表格資料, 重點是~~免費 (好用的話捐點小錢, 鼓勵 Allan 一下吧).
下載 dataTables 請連至下列網址, 目前版本為 1.9.4 :

http://www.datatables.net/download/

將 DataTables-1.9.4.zip 解壓縮後, 在 media/js 目錄下可以找到兩個 dataTables 程式, 其中 jquery.dataTables.js 原始檔 (約 370K), 而 jquery.dataTables.min.js 則是壓縮檔 (約 70 K), 要研究人家怎麼寫的, 請參考原始檔, 我們應用上只要將壓縮檔放到專案的 jquery 目錄即可, 與 jQuery 主檔放在一塊. 另外在 media/css 目錄下有一個  jquery.dataTables.css 檔, 此檔也是放到專案的 jquery 目錄下 :

匯入函式庫

<link href="jquery/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<link href="jquery/jquery.dataTables.css" rel="stylesheet">
<script type="text/javascript" src="jquery/jquery.min.js"></script>
<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
<script type="text/javascript" src="jquery/jquery.dataTables.min.js"></script>


如果我們的專案是放在 Internet 上, 那麼也可以使用 微軟的 CDN 來匯入函式庫 :

從微軟 CDN 匯入函式庫

<link href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.10.2/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<link href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css" rel="stylesheet">
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.0.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.10.2/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>


函式庫準備妥當後, 要讓 dataTables 能正常工作, 還有一個先決條件, 我們的 Table 元素裡一定要包含格式正確的 <thead> 與 <tbody> (但不要求有 <tfoot>), 例如 :

<table id="table1">
    <thead>
        <tr>
            <th>股票名稱</th>
            <th>股票名稱</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>台積電</td>
            <td>2330</td>
        </tr>
        <tr>
            <td>中華電</td>
            <td>2412</td>
        </tr>
    </tbody>
</table>

這樣只要取得 Table 元素的 jQuery 物件, 呼叫其 dataTable() 方法即可 (注意喔, 是單數的 dataTable, 不是複數的 dataTables) :

$(document).ready(function(){
    $("#table1").dataTable();
    });

測試範例 1 : http://tony1966.xyz/test/jquerytest/jquerytest/datatable_1.htm [看原始碼]

看到了嗎? 點一下各欄位表頭, 就會以該欄位值來排序, 也可以在右上角輸入關鍵字對整個表格做搜尋過濾, 還具有分頁功能 (但我們資料太少, 沒頁可分啦).
在範例 1 中, 我們在呼叫 dataTable() 方法時未傳入任何參數, 這樣 dataTables 套件會套用預設值, 預設是英文介面 (這是指 DataTables 的操作部分, 表格內容部分的語言仍然由我們決定). 要如何才能將 dataTables 的操作介面改成繁體中文呢 (也就是本地化, Localization)? 這就必須設定其參數物件中的 oLanguage 選項了. dataTables 的參數是一個物件實體, 每一個選項名稱就是其屬性. 在官網的 Usage/Internationalization 項下, 可以找到選項物件 oLanguage 的各屬性的說明, 但其中與本地化有關之屬性只有如下八個 (第八個還有跟分頁有關的 4 個次屬性), 下列便是繁體中文化的設定 :

var opt={"oLanguage":{"sProcessing":"處理中...",
                                     "sLengthMenu":"顯示 _MENU_ 項結果",
                                     "sZeroRecords":"沒有匹配結果",
                                     "sInfo":"顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項",
                                     "sInfoEmpty":"顯示第 0 至 0 項結果,共 0 項",
                                     "sInfoFiltered":"(從 _MAX_ 項結果過濾)",
                                     "sSearch":"搜索:",
                                     "oPaginate":{"sFirst":"首頁",
                                                          "sPrevious":"上頁",
                                                          "sNext":"下頁",
                                                          "sLast":"尾頁"}
                                     }
               };
$("#table1").dataTable(opt);

注意, 上面的中文字都可以改, 但 _MAX_, _TOTAL 等等都是變數, 不可以改或拿掉. 實際測試如範例 2. 有沒有注意到 dataTables 的選項名稱有一種規律, 凡是屬性值為字串者都以 "s" 開頭 (string), 而屬性值為物件者都以 "o" 開頭 (object)? 其實這是源自全錄公司的 Hungarian notation (匈牙利標示法), 從開頭的 1, 2 個字元, 就知道它的屬性值是哪種資料型態. 不過許多大師不太認同這種標示法, Linux 祖師爺 Linus Torvalds 甚至形容這種作法為 "腦殘 (brain damaged)". 我個人是覺得如果一個參數名稱可以放兩種以上資料類型時就會有點混亂. 
dataTables 所使用的字頭如下 :

 字頭saaafnfn 
 資料類型 stringobjectarray (1維)array (2維)integer float bolean node function

測試範例 2 : http://tony1966.xyz/test/jquerytest/datatable_2.htm [看原始碼]

如果網頁中有好幾個表格, 每一個都得設定 oLanguage 選項的本地化屬性會很煩, 其實只要把 oLanguage 的屬性值, 即 "{sProcessing .... }" 部分存成一個文字檔, 例如繁體中文化檔案 dataTables.zh-tw.txt 內容如下 :

{"sProcessing":"處理中...",
 "sLengthMenu":"顯示 _MENU_ 項結果",
 "sZeroRecords":"沒有匹配結果",
 "sInfo":"顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項",
 "sInfoEmpty":"顯示第 0 至 0 項結果,共 0 項",
 "sInfoFiltered":"(從 _MAX_ 項結果過濾)",
 "sSearch":"搜索:",
 "oPaginate":{"sFirst":"首頁",
                        "sPrevious":"上頁",
                        "sNext":"下頁",
                        "sLast":"尾頁"
                        }
 }

再將 oLanguage 的 sUrl 屬性設為此檔案位址即可 :

$(document).ready(function(){ 
    var opt={"oLanguage":{"sUrl":"dataTables.arabic.txt"}};
    $("#table1").dataTable(opt);
    });

dataTables 已經為各語言製作了本地化選項值, 可以在 Plug-ins/internationalization 下找到, 請點選語言名稱下的 Show details, 再複製其內容, 然後存成 utf-8 格式之純文字檔案, 再上傳到伺服器即可. 範例 3 是以這種方式對繁體中文, 日文, 以及阿拉伯文進行本地化. 

測試範例 3-1 (繁體) : http://tony1966.xyz/test/jquerytest/datatable_3_1.htm [看原始碼]
測試範例 3-2 (日文) : http://tony1966.xyz/test/jquerytest/datatable_3_2.htm [看原始碼]
測試範例 3-3 (阿拉伯文) : http://tony1966.xyz/test/jquerytest/datatable_3_3.htm [看原始碼]

接著來看 bJqueryUI 選項, 這是用來設定是否要套用 jQuery UI 布景主題, 預設為 false (不套用). 如果我們有匯入 jQuery UI 函式庫, 那麼只要將此選項設為 true 即可套用所選之布景. 將範例 3-1 加上 bJqueryUI 選項即成下列範例 4 (要特別注意大小寫, 其中 J/Q/U/I 為大寫, 若寫成小寫將不會動) :

$(document).ready(function(){ 
   var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
                  "bJQueryUI":true
                  };
   $("#table1").dataTable(opt);
   });

測試範例 4 : http://tony1966.xyz/test/jquerytest/datatable_4.htm [看原始碼]

在範例 4 中, 將 bJQueryUI 設為 true 後, 因為我們載入的是 hot-sneaks 布景, 所以整個表格就套上了 hot-sneaks 的主題了, 這樣是不是比較有 fu 了呢? 其實 jQuery UI 提供了24 個佈景, 把範例 4 加上一個下拉式選單從微軟的 CDN 挑選佈景 css 檔, 改成 PHP 程式如範例 5, 看看哪一個佈景比較順眼 :

測試範例 5 : http://tony1966.xyz/test/jquerytest/datatable_5.php [看原始碼]

以上測試都以 DOM 元素中的表格為資料來源 (也就是 HTML 的 TABLE 啦), 其實, dataTables 可以從四種來源取得表格資料 :
  1. DOM
  2. 陣列
  3. Ajax JSON
  4. 後端伺服器處理分頁過濾與搜尋
現在就來看看如何利用陣列來提供表格內容. 以陣列作為資料來源時, 表格元素只要留下 table 即可, 不需要 thead 與 tbody, dataTables 物件會自動建立 :

<table id="table1"></table>

表格的欄位標題要使用選項 aoColumns 來指定, 從開頭的 "ao" 可知此為一物件陣列 (array of objects), 其屬性名稱 "sTitle" 用來設定欄位的標題名稱, 例如 "股票名稱" 等等.  而表格內容則要用選項 aaData 來設定, 從起首的 "aa" 可知此為二維陣列, 其中每一個元素都是一個一維陣列, 表示一筆或一列資料, 其順序與 aoColumns 中的 sTitle 屬性相對應 :

var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
              "bJQueryUI":true,
              "aoColumns":[{"sTitle":"股票名稱"},
                                   {"sTitle":"股票代號"},
                                   {"sTitle":"收盤價 (元)"},
                                   {"sTitle":"成交量 (張)"}],
              "aaData":[["台積電","2330",111.5,19268],
                             ["中華電","2412",95.1,7096],
                            ["中碳","1723",145.0,317],
                            ["創見","2451",104.0,459],
                            ["華擎","3515",104.0,95],
                            ["訊連","5203",98.5,326]]
             };
$("#table1").dataTable(opt);


測試範例 6 : http://tony1966.xyz/test/jquerytest/datatable_6.htm [看原始碼]

從範例 6 可知, 所呈現的表格與上面直接寫在 HTML 裡的效果完全一樣. 但是當表格很大時, 若表格內容直接寫在 HTML 中, 則瀏覽器要建立 DOM 樹會花比較多時間, 這時改用陣列可以加快網頁呈現之速度.

其實 aaData 選項除了用二維陣列以外, 像 aoColumns 那樣使用物件陣列也是可以的, 這時選項 aaData 裡的每一欄位資料都要加上欄位名稱作為屬性, 而且 aoColumns 選項也要多一個屬性 mData, 用來設定每一個欄位對應 aaData 中的哪一個屬性 :


var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":true,
               "aoColumns":[{"sTitle":"股票名稱","mData":"stock_name"},
                                      {"sTitle":"股票代號","mData":"stock_id"},
                                      {"sTitle":"收盤價 (元)","mData":"close"},
                                      {"sTitle":"成交量 (張)","mData":"volumn"}],
               "aaData":[{"stock_name":"台積電",
                                "stock_id":"2330",
                                "close":111.5,
                                "volumn":19268},
                               {"stock_name":"中華電",
                                "stock_id":"2412",
                                "close":95.1,
                                "volumn":7096},
                               {"stock_name":"中碳",
                                "stock_id":"1723",
                                "close":145.0,
                                "volumn":317},
                               {"stock_name":"創見",
"stock_id":"2451",
                             "close":104.0,
                                "volumn":459},
                               {"stock_name":"華擎",
                                "stock_id":"3515",
                                "close":104.0,
                                "volumn":95},
                               {"stock_name":"訊連",
                                "stock_id":"5203",
                                "close":98.5,
                                "volumn":326}]
                 };
$("#table1").dataTable(opt);


測試範例 7 : http://tony1966.xyz/test/jquerytest/datatable_7.htm [看原始碼]

我們把範例 6 稍做修改成範例 7, 可見結果完全一樣, 但我覺得範例 7 比較囉唆, 還是範例 6 較精簡. 所以忘了範例 7 吧, 此處純粹只是測試一下而已, 沒有人願意捨簡就繁啊!

接下來, 項莊舞劍意在沛公, 重點來了, 我們來看第三種資料來源, 也就是透過 Ajax 由遠端資料庫提供表格內容. 這就要用到選項 sAjaxSource 了, 此選項是一個 URL 字串, 指向遠端伺服器的一個能產生 JSON 內容的程式. 這個程式要能輸出一個含有 aaData 單一屬性的物件, 其值為一個表示表格內容的二維陣列, 例如我們要從遠端伺服器的 stocks_list 資料表取出全部台股上市公司股票名稱與代號, 其 JSON 格式如下 :

{"aaData":[["\u5bcc\u90a6","0015"],["\u53f0\u706350","0050"],...,["\u65fa\u65fa\u4fdd","2816"]]}

此 JSON 只有 aaData 一個屬性, 其值為二維陣列, 每一個元素代表表格的一列資料, 其第一欄位為股票名稱, 第二欄位為股票代號. 此資料表 stocks_list 的製作方法詳見 "jQuery UI 的自動完成器 autocomplete 測試" 中的範例 4 說明, 此處不再贅述. 產生此 JSON 輸出的 PHP 程式 get_stocks_list_aa.php 如下 :


<?php
header('Content-Type: text/html;charset=UTF-8');
$host="mysql.1freehosting.com"; //MySQL 主機位址
$username="tony1966_test"; //MySQL 使用者名稱
$password="123456"; //MySQL 使用者密碼
$database="testdb"; //資料庫名稱
$conn=mysql_connect($host, $username, $password); 
mysql_query("SET NAMES 'utf8'"); //設定查詢所用之字元集為 utf-8
mysql_select_db($database, $conn); //開啟資料庫
$SQL="SELECT * FROM `stocks_list`"; 
$result=mysql_query($SQL, $conn); //執行 SQL 指令
$stock=array(); //儲存表格內容之二維陣列
for ($i=0; $i<mysql_numrows($result); $i++) { //走訪紀錄集 (列)
     $row=mysql_fetch_array($result); //取得列陣列
     $stock_name=$row["stock_name"];
     $stock_id=$row["stock_id"];
     $stock[$i]=array($stock_name, $stock_id); //存入二維陣列
     } //end of for
$arr["aaData"]=$stock; //表格內容存入關聯式陣列echo json_encode($arr);  //將陣列轉成 JSON 資料格式傳回
?>

上述程式中, 我們從 stocks_list 資料表取得全部股票之名稱與代號後, 先存入二維陣列 $stock 中, 最後將其放入一個一維之關聯式陣列, 索引為 "aaData" (所以 $arr 陣列是三維), 這樣子在將其傳入 json_encode() 後, 就會被轉成具有單一屬性 aaData 的 JSON 物件了. 

然後回到網頁部分, 同樣地, 我們只需要一個空的 TABLE 元素即可, 不需要 THEAD 與 TBODY 元素, dataTables 物件會自動產生. jQuery 程式設定如下 :


var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
              "bJQueryUI":true,
              "bProcessing":true,
              "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
              "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
              };
$("#table1").dataTable(opt);

在上面程式中, 選項 aoColumns 用來設定表格標題, 而選項 sAjaxSource 則用來設定提供表格內容的遠端伺服器程式的 URL, 這樣 dataTables 物件會自動發出 Ajax 要求向遠端伺服器擷取表格內容 (預設是用 GET 方法, 可以用 sServerMethod 選項設為 "POST" 即可). 然後預期伺服器回應一個含有 "aaData" 屬性之 JSON 資, 注意 aoColumns 中的標題順序必須與 JSON 內容的欄位相對應. 為什麼要用 "aaData" 呢? 這其實是 dataTables 套件的預設值, 這可以利用 sAjaxDataProp 選項去更改, 例如 "sAjaxDataProp":"data" 表示伺服器傳回的 JSON 資料必須以 "data" 作為屬性名稱, 這樣上面的後端程式 get_stocks_list_5.php 最後一行就要配合改為 $arr["data"]=$stock 才行. 
但我覺得不要無事生事, 一切用預設值最省時省事. 
另外有沒有注意到, 這裡還多了一個選項 bProcessing (預設為 false), 設為 true 的話, 當表格資料很多, 需要一些時間處理 (例如排序) 時, 表格上會顯示 "處理中 ..." 
完整範例請看範例 8.

測試範例 8 : http://tony1966.xyz/test/jquerytest/datatable_8.htm [看原始碼]

當然我們也可以自行用 jQuery 的公用函式 $.ajax 來取得表格內容, 這樣就不能用 sAjaxSource 選項了, 而要改用 aaData 選項. 顧名思義, aaData 需要一個二維陣列當作其值, 所以上述的 get_stocks_list_aa.php 不能用, 因為那是三維陣列, 必須做一些修改為 get_stocks_list_6.php 如下 :

<?php
header('Content-Type: text/html;charset=UTF-8');
$host="mysql.1freehosting.com"; //MySQL 主機位址
$username="tony1966_test"; //MySQL 使用者名稱
$password="123456"; //MySQL 使用者密碼
$database="testdb"; //資料庫名稱
$conn=mysql_connect($host, $username, $password); //建立連線
mysql_query("SET NAMES 'utf8'"); //設定查詢所用之字元集為 utf-8
mysql_select_db($database, $conn); //開啟資料庫
$SQL="SELECT * FROM `stocks_list`"; 
$result=mysql_query($SQL, $conn); //執行 SQL 指令
$stock=array(); 
for ($i=0; $i<mysql_numrows($result); $i++) { //走訪紀錄集 (列)
     $row=mysql_fetch_array($result); //取得列陣列
     $stock_name=$row["stock_name"];
     $stock_id=$row["stock_id"];
     $stock[$i]=array($stock_name, $stock_id); //存入二維陣列
     } //end of for
echo json_encode($stock);  //將陣列轉成 JSON 資料格式傳回
?>

只要把二維陣列 $stock 直接轉成 JSON 格式傳回即可. 而 jQuery 程式部分則修改為 Ajax, 我們把遠端傳回的 JSON 資料 (參數 resultData) 設定給 aaData 選項就可以了 (當然也不要忘了 aoColumns 選項所負責的表格標題) :


$.ajax({
  type: "POST",
  url: "http://tony1966.xyz/test/jquerytest/get_stocks_list_6.php",
  data: "",
  dataType: "json",
  success: function(resultData) {
      var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
            "bJQueryUI":true,
            "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
            "aaData": resultData
            };         
       $("#table1").dataTable(opt);
       }
 });

完整測試範例請看範例 9:

測試範例 9 : http://tony1966.xyz/test/jquerytest/datatable_9.htm [看原始碼]

測試完第三種資料來源 (從後端伺服器取得表格內容之 JSON 資料) 後, 接著來看看第四種資料來源. 
第四種方式其實與第三種一樣都是從後端伺服器取得表格內容, 但差別是第四種方式把分頁, 過濾與搜尋功能都交由後端程式處理, dataTables 只是一個事件模組與呈現模組. 這種方式要將  bServerSide 選項設為 true, 同時如方式三那樣設定 sAjaxSource 選項為後端伺服器程式之 URL. 但本文不會對第四種方式進行測試, 因為那太複雜啦, 有違我們使用套件的初衷-使網頁應用簡化, 可以交給 dataTables 的事為何還要自己做? (果然, 科技始終來自於惰性啊!).

接下來我們要測試跟分頁功能有關的選項 (因為表格內容夠多了, 有頁可分了). 分頁相關選項有四個 : 
  1. iDisplayLength (數字, 預設 10)
  2. bLengthChange (true/false, 預設 true)
  3. aLengthMenu (1/2 維陣列, 預設 [10, 25, 50, 100])
  4. sPaginationType ("two_button"/"full_numbers", 預設 "two_button")
  5. bPaginate (true/false, 預設 true)
首先, iDisplayLength 這選項用來設定每一頁顯示幾列資料, 預設是 10 列, 所以 100 筆資料就會被分成 10 頁. 而 bLengthChange 選項用來控制是否要在表格左上角顯示一個可以更改每頁顯示列數的下拉式選單, 其選項值有 10, 25, 50, 與 100. 當使用者選擇時, 其值就會覆蓋 iDisplayLength  選項所設之預設值 10. 如果我們想要固定顯示每頁 80 列, 那麼就要先將 bLengthChange 設為 false 關掉左上角的下拉式選單, 然後將 iDisplayLength 設為 80 即可, 如下列範例 10 所示 (由範例 8 修改而來) :

var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":true,
               "bLengthChange":false,
               "iDisplayLength": 80,
               "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
               "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
               };
$("#table1").dataTable(opt);

測試範例 10-1 : http://tony1966.xyz/test/jquerytest/datatable_10_1.htm [看原始碼]

當 bLengthChange 選項設為 true, 如果對左上角的 10, 25,50,100 預設選單不滿意的話, 可以用 aLengthMenu 選項來更改. 此選項可以是一維陣列, 例如預設的 [10, 25,50,100], 這時選單的 option 元素內容與值 (value) 是一樣的. 如果是二維陣列的話, 例如下面這樣 :

"aLengthMenu":[[5, 30, 60, -1], [5, 30, 60, "All"]]

其中前面元素是 option 的值 (value, -1 表示全部), 後面是顯示 (option 的內容). 請看測試範例 10-2 :

測試範例 10-2 : http://tony1966.xyz/test/jquerytest/datatable_10_2.htm [看原始碼]

而 sPaginationType 選項是指右下角的分頁控制按鈕類型, 預設是 "two_button", 亦即只有上一頁與下一頁兩個按鈕, 上面所有範例皆是如此. 如果設為 "full_numbers", 則除了上頁, 下頁外, 還有首頁, 尾頁, 以及目前頁數前後 2 頁的按鈕, 如下列範例 11 :

var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":false,
               "sPaginationType":"full_numbers",
               "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
               "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
               };
$("#table1").dataTable(opt);

測試範例 11 : http://tony1966.xyz/test/jquerytest/datatable_11.htm [看原始碼]

有沒有注意到範例 11 中我們將 bJQueryUI 選項關閉了 (不套用 jQuery UI 佈景)? 這似乎是 dataTables 的一個小臭蟲, 如果套用主題佈景的話, "full_numbers" 的分頁按鈕會擠在一團, 如下列範例 12 所示 :

測試範例 12 : http://tony1966.xyz/test/jquerytest/datatable_12.htm [看原始碼]

接著來看 bPaginate 選項, 這是用來打開或關閉分頁功能的, 如果設為 false, 則其他分頁相關選項都將失去作用, 例如範例 12 所示 :

var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":true,
               "bPaginate":false,
               "bLengthChange":true,
               "sPaginationType":"full_numbers",
               "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
               "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
               };
$("#table1").dataTable(opt);

測試範例 13 : http://tony1966.xyz/test/jquerytest/datatable_13.htm [看原始碼]

可見只要 bPaginate 設為 false, 則左上角的每頁列數選單, 以及右下角的分頁切換按鈕全都不見了, 全部資料以一頁呈現. 

接下來看看跟卷軸有關的三個選項 :
  1. sScrollY (字串, 垂直卷軸, 預設值 "")
  2. bScrollCollapse (true/false, 卷軸高度設定瓦解, 預設 false)
  3. sScrollX (字串, 水平卷軸, 預設值 "")
如果不想分頁, 但表格資料又有點大, 把網頁撐得很長, 能不能用卷軸來控制呢? 可以的, 這要用到 sScrollY 選項 (字串), 它是用來控制垂直卷軸的 (但要配合將 bPaginate 設為 false 才行), 預設值為空字串 (無垂直卷軸), 其值可以為 CSS 的任何長度表示, 例如 "sScrollY":"400px" 表示, 表格內容部分將被放到一個 400px 的 viewport 容器裡, 只要資料高度超過 400px, 右方便會出現垂直卷軸. 我們將範例 13 稍微修改為範例 14-1 如下 :


var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
              "bJQueryUI":true,
              "bPaginate":false,
              "sScrollY":"400px",
              "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
              "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
              };
$("#table1").dataTable(opt);

測試範例 14-1 : http://tony1966.xyz/test/jquerytest/datatable_14_1.htm [看原始碼]

看到了嗎? 由於我們的上市股票超過 800 支, 在取消分頁功能時網頁會很長, 但若設定 sScrollY 選項, 就可以將網頁限縮在一頁的高度, 然後用卷軸來移動視野. 這比瀏覽器本身卷軸好的地方是, 表頭欄位名稱會一直都在那兒不動, 不像上面範例 13, 往下拉時表頭欄位名稱就看不到啦! 

另外, 跟垂直捲軸很有關係的便是 bScrollCollapse 選項, 當設定垂直捲軸高度時, 若使用搜尋功能找出的資料高度小於卷軸高度時, 這是資料底端與表格底端就會一片空白, 看來很突兀, 如果把 bScrollCollapse 設為 true, 就能瓦解卷軸高度設定, 使得表格底部與資料底部相接, 當然如果搜尋出來的資料高度大於卷軸高度, 仍然被捲軸高度所限制. 例如下列範例 14-2 所示 :

var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
              "bJQueryUI":true,
              "bPaginate":false,
              "sScrollY":"400px",
              "bScrollCollapse":true,
              "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
              "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
              };
$("#table1").dataTable(opt);


測試範例 14-2 : http://tony1966.xyz/test/jquerytest/datatable_14_2.htm [看原始碼]

水平卷軸的設定也是類似, 不過它跟資料筆數無關, 也跟分頁功能無關, 而是欄位太多, 或欄位內資料太長, 以至於表格寬度向右撐破頁面, 這樣瀏覽器下頭就會出現水平卷軸. 利用 sScrollX 選項就能把表格內容放入指定寬度的 viewport 容器中, 由 dataTables 物件自己產生水平卷軸.

由於我們的 stocks_list 資料表只有兩個欄位, 所以將範例 1 稍作修改成範例 15. 為了產生水平卷軸效果, 我們在 table 元素外面再包一個 div 元素, 並將其寬度限制為 300px :


<div style="width:300px;">
  <table id="table1">
    <thead>
      <tr>
        <th>股票名稱</th>
        <th>股票代號</th>
        <th>收盤價 (元)</th>
        <th>成交量 (張)</th>
      </tr>
    </thead>
  <tbody>
    <tr>
      <td>台積電</td>
      <td>2330</td>
      <td>111.5</td>
      <td>19268</td>
    </tr>
  ...
  ...
  </table>
</div>

這樣整個表格就被 div 限制在 300px 的寬度, 然後設定 sScrollX 選項為 400px 如下 :

$(document).ready(function(){
  var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
           "bJQueryUI":true,
           "sScrollX":"400px"
           };
  $("#table1").dataTable(opt);
  });

完整程式碼請看範例 15 :

測試範例 15 : http://tony1966.xyz/test/jquerytest/datatable_15.htm [看原始碼]

範例 15 顯示, 由於我們只給予表格 300px 寬度空間 (利用 div 元素來限制), 但 sScrollX 卻要求 400px 的寬度來放表格內容, 撐破了水平寬度限制, 因此 dataTables 物件就產生水平卷軸來移動視野.

接下來看看跟欄位有關的四個選項 :
  1. sTitle (字串)
  2. sWidth (字串, "20%"/"20px")
  3. sType (字串, "string"/"numeric"/"date"/"html", 預設 "string")
  4. sClass (字串, 樣式類別的名稱, 預設 "")
其實這些是 aoColumns 選項中的子選項, 前面我們已經用過 sTitle 選項, 這是用來設定欄位標題的. 而 sWidth 則是用來設定欄位寬度的, 可用百分比如 "20%", 或長度如 "100px". 而 sType 則是用來設定欄位排序時比對用的資料類型, 有四種 : "string"/"numeric"/"date"/"html", 預設是 "string", 把資料當作字串來排序 (即使資料全部是數字). 選項 sClass 則是用來設定欄位的 CSS 樣式類別, 我們可以自行在網頁中定義一個樣式類別, 然後用 sClass 指定某欄位套用此樣式類別. 下列範例 16 中, 我們增加一個編輯欄位放在第一欄 (寬度 20px), 此欄位內放一個編輯筆的 gif 圖檔, 我們此欄位內容居中對齊, 且文字不會折回 (nowrap), 這可以用一個自訂樣式類別 editClass 來控制 :

.editClass {text-align:center;white-space:nowrap;}

而第二欄位 (股票名稱) 寬度設為 20%, 以字串排序, 第三欄 (股票代號) 為 80%, 以數值排序 :

var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":true,
               "aoColumns":[{"sTitle":"編輯","sWidth":"20px","sClass":"editClass"},
                                        {"sTitle":"股票名稱","sWidth":"20%","sType":"string"},
                                        {"sTitle":"股票代號","sWidth":"80%","sType":"numeric"}],
               "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_5.php"
               };
$("#table1").dataTable(opt);

當然後端程式也要配合修改, 增加輸出一個編輯欄位, 我們修改上面範例 10~14 所用的 get_stocks_list_aa.php, 加上編輯欄位為 get_stocks_list_5.php 如下 :



$stock=array(); 
for ($i=0; $i<mysql_numrows($result); $i++) { //走訪紀錄集 (列)
     $row=mysql_fetch_array($result); //取得列陣列
     $stock_name=$row["stock_name"];
     $stock_id=$row["stock_id"];
     $edit="<img src='edit.gif' style='border-width:0px;width:15px;height:15px;'>";
     $stock[$i]=array($edit, $stock_name, $stock_id);
     } //end of for
$arr["aaData"]=$stock;
echo json_encode($arr);  //將陣列轉成 JSON 資料格式傳回



測試範例 16 : http://tony1966.xyz/test/jquerytest/datatable_16.htm [看原始碼]

從範例 16 可知, 透過 sClass 的樣式設定, 把圖檔在 td 元素裡置中對齊了, 而 sType 的設定使第三欄股票代號排序完全以數值大小為依據, 與範例 13 的以字串排序不同, 例如範例 13 中, 006203 是排在 0061 後面 (當作字串逐字元排序), 而在範例 16 中, 006203 排在 6201 後面 (當作數值排序).

以上都只談到選項的用法, 還沒介紹方法. 現在來看看 dataTables 套件最常用的方法 (API) : fnGetData(). 此處我們要用一個常見的應用來介紹此方法, 就是當我們點一下表格中的某列, 可以連結到某一個網頁, 這在以前的做法通常是在某一列的某欄資料加上超連結, 或是用 script 更改 window.location.href 屬性值. 下列範例 17 我們就來為上面範例 14 的股票列表添加一個功能, 當使用者點選某一列時, 就開啟一個新畫面, 顯示 Yahoo 股市網站中該股的當日行情.  Yahoo 股市當日行情的網址格式如下 (以中華電為例) :

http://tw.stock.yahoo.com/q/q?s=2412

所以, 我們只要取得股票代號就可以製作該股票的 URL 了. 但要如何取得使用者點選的那一列的股票代號呢? 這要從 dataTables 物件著手. 上面的所有範例中, 我們都呼叫了表格元素的 jQuery 物件的 dataTable() 方法, 這方法其實是有傳回值的, 它會傳回 dataTables 物件 :

var oTable=$("#table1").dataTable();  //傳回 dataTables 物件

利用此 dataTables 物件就可以知道使用者點了哪一列資料, 然後讀取該列第二欄位就是股票代號了. dataTables 物件有一個 $ 方法, 可用來執行 jQuery 的選擇器功能, 可以選取表格的 tbody 內容 , 例如列 (tr) 或 元素 (td), 然後我們就可以為選取的列加上 click 動作, 再用 fnGetData() 這個方法來取得列的內容. fnGetData() 方法可以傳入 tr 或 td 節點元素, 若傳入 td 節點, 則傳回該 td 的內容; 若傳入 tr 節點, 則傳回一陣列, 其元素就是該 tr 列中的所有 td 內容. 此處我們傳入 this 表示 tr 節點, 這樣就會顯示該列所有 td 內容, 例如 "台積電,2330,111.5,19268". 
我們將範例 1 修改為範例 17 如下 :


$(document).ready(function(){ 
   var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
                 "bJQueryUI":true
                 };
var oTable=$("#table1").dataTable(opt);
oTable.$('tr').click(function() {
    var row=oTable.fnGetData(this); //取得 tr 內容, 傳回陣列
    alert(row); //顯示陣列內容
    alert(row[1]); //顯示
    });
});

測試範例 17 : http://tony1966.xyz/test/jquerytest/datatable_17.htm [看原始碼]

範例 17 顯示, 點選任一列就會顯示該列所有 td 的內容以及第二個 td (股票代號) 內容. 所以我們就可以利用 row[1] 來製作超連結了, 如範例 18 所示 :


$(document).ready(function(){ 
   var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
                 "bJQueryUI":true
                 };
var oTable=$("#table1").dataTable(opt);
oTable.$('tr').click(function() {
    var row=oTable.fnGetData(this); //取得 tr 內容, 傳回陣列
    var url="http://tw.stock.yahoo.com/q/q?s=" + row[1]; //Yahoo 股市當日行情 url
    window.open(url); //開啟新視窗
    });
});

測試範例 18 : http://tony1966.xyz/test/jquerytest/datatable_18.htm [看原始碼]

範例 18 中, 點任何一列就會開啟 Yahoo 股市網站上該股的當日行情. 一切似乎都很美好不是嗎? 
但是有沒有注意到, 範例 17 與 18 都是以網頁中的表格內容為資料來源, 如果改從遠端伺服器取得表格資料, 上述用 $("tr").click 綁定 click 事件的作法就破功了, 點任何一列都不會動, 我們把範例 14 稍作修改為下列範例 19  :


var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
              "bJQueryUI":true,
              "bPaginate":false,
              "sScrollY":"400px",
              "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
              "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
              };

var oTable=$("#table1").dataTable(opt);
oTable.$('tr').click(function() {
    var row=oTable.fnGetData(this); //取得 tr 內容, 傳回陣列
    var url="http://tw.stock.yahoo.com/q/q?s=" + row[1]; //Yahoo 股市當日行情 url
    window.open(url); //開啟新視窗
    });

測試範例 19 : http://tony1966.xyz/test/jquerytest/datatable_19.htm [看原始碼]

沒錯吧! 範例 19 顯示, 當表格資料來源是遠端伺服器提供的 JSON 資料時, 用 $("tr").click 綁定 click 事件是沒作用的. 根據 dataTables 套件作者 Allan 的回覆是, 要用 on 方法綁定事件 (jQuery 1.7 開始) 才行, 詳情請參考 dataTables 論壇上的 "Use fnGetData w/Ajax data source" 這篇文章. 所以把範例 19 改為如下的範例 20 :


var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
              "bJQueryUI":true,
              "bPaginate":false,
              "sScrollY":"400px",
              "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
              "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
              };
var oTable=$("#table1").dataTable(opt);
oTable.on('click','tr',function() {
    var row=oTable.fnGetData(this); //取得 tr 內容, 傳回陣列
    var url="http://tw.stock.yahoo.com/q/q?s=" + row[1]; //Yahoo 股市當日行情 url
    window.open(url); //開啟新視窗
    });

測試範例 20 : http://tony1966.xyz/test/jquerytest/datatable_20.htm [看原始碼]

範例 20 顯示這招奏效了.  關於 jQuery 的 on() 方法, 可參考這篇 "jQuery 1.7筆記".

最後, 我們以範例 21 將以上測試作個總結, 以範例 20 的開啟 Yahoo 今日行情網頁為基礎, 結合範例 16 具有編輯欄位的表格, 並希望給這些編輯圖樣加上超連結, 點擊後會帶出 stock_id 與 stock_name 兩個變數給另一個編輯網頁 edit_stocks_list.php 如下  :


<form id="edit_form">
  <p>股票代號 : <input type="text" id="stock_id" value="<?php echo $stock_id ?>"></p>
  <p>股票名稱 : <input type="text" id="stock_name" value="<?php echo $stock_name ?>"></p>
  <p><input type="button" id="submit" value="確定"></p>
</form>
<script language="JavaScript">
  $(document).ready(function(){ 
    $("#submit").click(function() {
      alert("更新!");
      });
    });
  </script>

同時把範例 16 中的後端程式 get_stocks_list_5.php 修改為  get_stocks_list_7.php, 給圖檔添加超連結 :


for ($i=0; $i<mysql_numrows($result); $i++) { //走訪紀錄集 (列)
     $row=mysql_fetch_array($result); //取得列陣列
     $stock_name=$row["stock_name"];
     $stock_id=$row["stock_id"];
     $edit="<a href='edit_stocks_list.php?stock_id=".$stock_id."&stock_name=".
               $stock_name."' target='_blank'><img src='edit.gif' ".
               "style='border-width:0px;width:15px;height:15px;'></a>";
     $stock[$i]=array($edit, $stock_name, $stock_id);
     } //end of for
$arr["aaData"]=$stock;
echo json_encode($arr);  //將陣列轉成 JSON 資料格式傳回

而 jQuery 程式部分則必須修改, 在範例 20 中我們是給整列 tr 綁定 click 事件, 但是因為現在第一欄放了一個有超連結的編輯圖檔, 這樣編輯超連結就會被 tr 的 click 事件覆蓋過去, 亦即點擊編輯圖檔時不會開啟編輯網頁了, 而是開啟 Yahoo 每日行情網頁. 解決此問題的方法有二, 那就是也在後端程式中對 stock_id 與 stock_name 欄位加上超連結, 第二個方法是修改功能, 就是不要給 tr 綁定 click 事件, 改成給 td 綁定 click 事件, 而且只有點擊 stock_id 欄位時才開啟 Yahoo 每日行情網頁, 具體作法是判斷 fnGetData() 方法讀取 td 的內容, 如果是數字 (即 stock_id), 就開啟 Yahoo 每日行情網頁, 若不是數字 (stock_name 與編輯欄位) 就不動作 :


    $(document).ready(function(){ 
      var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":true,
               "bPaginate":false,
               "sScrollY":"400px",
               "aoColumns":[{"sTitle":"編輯","sWidth":"20px","sClass":"editClass"},
                                      {"sTitle":"股票名稱"},
                                      {"sTitle":"股票代號"}],
               "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_7.php"
               };
      oTable.on('click','td',function() {
          var cell=oTable.fnGetData(this); //取得 td 內容
          if (!isNaN(cell)) { //點擊股票代號欄位
              var url="http://tw.stock.yahoo.com/q/q?s=" + cell;
              window.open(url);
             }
         });
      });

完整程式碼如範例 21 :

測試範例 21 : http://tony1966.xyz/test/jquerytest/datatable_21.htm [看原始碼]

dataTables 套件中還有許多選項, 但我想上面所測試的應該是專案開發中最常用到的了, 其他的請參考官網的 Usage 與 API 項目下的說明, 下列連結是 dataTables 套件所有選項與方法的列表 :
http://datatables.net/ref

~全劇終

** 編後語 :

在範例 11 中提到一個 dataTables 的 bug, 若分頁時同時套用 jQuery UI, 則右下角的分頁按鈕會擠成一團 (no padding), 根本無法正常選擇分頁. 本來要寫信給 Allan, 但昨日在論壇找到解藥了, 原來套用 jQuery UI 時比較合用的 css 樣式表不是本文開頭所用的 media\css 下的 jquery.dataTables.css, 而是同目錄下的 jquery.dataTables_themeroller.css, 原文詳見 :

http://datatables.net/forums/discussion/8898/full-number-pagination-jquery-ui/p1

所以上面匯入函式庫的部分要改為如下 :


匯入函式庫

<link href="jquery/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<link href="jquery/jquery.dataTables_themeroller.css" rel="stylesheet">
<script type="text/javascript" src="jquery/jquery.min.js"></script>
<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
<script type="text/javascript" src="jquery/jquery.dataTables.min.js"></script>


而從微軟 CDN 匯入的話, 也要改成 :


從微軟 CDN 匯入函式庫

<link href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.10.2/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<link href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables_themeroller.css" rel="stylesheet">
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.0.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.10.2/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>



上面套用 jquery.dataTables.css 的測試就不再修改了 (做個對照), 這裡將範例 11 做些修改, 把 bJGueryUI 選項打開, 改為匯入 jquery.dataTables_themeroller.css 樣式表, 同時加上主題布景選擇器, 如下列測試範例 11-1  :


var opt={"oLanguage":{"sUrl":"dataTables.zh-tw.txt"},
               "bJQueryUI":true,
               "sPaginationType":"full_numbers",
               "aoColumns":[{"sTitle":"股票名稱"},{"sTitle":"股票代號"}],
               "sAjaxSource":"http://tony1966.xyz/test/jquerytest/get_stocks_list_aa.php"
               };
$("#table1").dataTable(opt);


測試範例 11-1 : http://tony1966.xyz/test/jquerytest/datatable_11_1.php [看原始碼]

呵呵, 經過這番更改後, 果然變成美美的分頁按鈕了. 除了 dark-hive 與 black-tie 主題太暗, 看不清楚分頁按鈕外, 其他都還不錯.
那如果取消分頁, 改用垂直卷軸, 套用 jquery.dataTables_themeroller.css 樣式表效果如何? 我們修改範例 14-2, 只是改了其中 css 匯入部分如範例 14-3 :

測試範例 14-3 : http://tony1966.xyz/test/jquerytest/datatable_14_3.htm [看原始碼]

感覺有比較好一點, 至少欄位標題沒那麼厚, 上下框框高度加大, 還不錯啦.


2020-07-24 補充 :

jQuery UI dataTables 外掛早已經有了新版, 參見 :

# 發現新的 jQuery UI Datatable

用法與上面舊版的有些不同, 參考 :

https://datatables.net/