前陣子在專案中用了jQuery AutoComplete Plugin,感覺甚好,我想將來很可能會繼續用在其他專案上,索性做了一個範例懶人包以備未來不時之需,利人也利已。(我預估自己大概下個月就會忘記這次是怎麼寫出來的,所以這個懶人包對我來說也粉重要)
放了一個線上的範例網頁讓大家試敲,你可以輸入電子類股的股票代號、中文/英文股票名稱,網頁會提供提示,選取後會在左邊填入股票代號、右邊填入中文名稱。如下圖剖析,其實它是用<ul><li>去建構清單,而我特別框出selectValue,extra,會呼應到稍後提到findValue()函數中取值的邏輯。
程式的簡單說明如下。
前端HTML中主要透過$("...").autocomplete()的方式在Textbox掛上自動完成功能:
(註: 原版的jquery.autocomplete.js有中文相容的問題,所以我用的是對岸網友修改過的版本,我自己則加了一個noCache參數。文件上說cacheLength設為1就不會做Cache,但我觀察結果似乎不然,也許是版本不同所致。當資料筆數很多時,Cache在Script Side的做法就會變得不合適,因此我加了一個參數鋸箭解決Cache問題。)
(註: 原版的jquery.autocomplete.js有中文相容的問題,所以我用的是對岸網友修改過的版本,我自己則加了一個noCache參數。文件上說cacheLength設為1就不會做Cache,但我觀察結果似乎不然,也許是版本不同所致。當資料筆數很多時,Cache在Script Side的做法就會變得不合適,因此我加了一個參數鋸箭解決Cache問題。)
排版顯示純文字
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jQuery自動輸入完成懶人包</title>
<script src="jquery-1.3.2.js" type="text/javascript"></script>
<script src="jquery.autocomplete.js" type="text/javascript"></script>
<link href="jquery.autocomplete.css" rel="stylesheet" type="text/css" />
<style type="text/css">
input
{
width: 60px;
margin-left: 5px;
}
</style>
<script type="text/javascript">
$(function() {
//選項說明: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions
$("#txtSymbol").autocomplete("ACDataSrc.aspx",
{
delay: 10,
width: 120,
minChars: 1, //至少輸入幾個字元才開始給提示?
matchSubset: false,
matchContains: false,
cacheLength: 0,
noCache: true, //黑暗版自訂參數,每次都重新連後端查詢(適用總資料筆數很多時)
onItemSelect: findValue,
onFindValue: findValue,
formatItem: function(row) {
return "<div style='height:12px'><div style='float:left'>" + row[0] +
"</div><div style='float:right;padding-right:5px;'>" +
row[1] + "/" + row[2] + "</div></div>";
},
autoFill: false,
mustMatch: true //是否允許輸入提示清單上沒有的值?
});
function findValue(li) {
if (li == null) return alert("No match!");
$("#txtSymbol").val(li.extra[0]);
$("#txtCName").val(li.extra[1]);
}
});
</script>
</head>
<body>
<input type="text" id="txtSymbol" />
<input type="text" id="txtCName" readonly="readonly" style="background-color: #cccccc;" />
</body>
</html>
另外,我寫了一隻ACDataSrc.aspx負責餵資料: (為力求單純,股票資料是用字串列出股票清單,實務上應該會以資料庫查詢取代之)
排版顯示純文字
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.IO;
public partial class jQueryAutoComp_ACDataSrc : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//使用者目前輸入的文字預設以q傳入
string q = Request["q"] ?? "";
if (q.Length > 0)
{
DataTable t = getStockData();
DataView dv = new DataView(t);
//利用LIKE做查詢
dv.RowFilter = "Key LIKE '" + q.Replace("'", "''") + "%'";
dv.Sort = "Key, Symbol";
List<string> lst = new List<string>();
lst.Add("");
foreach (DataRowView drv in dv)
{
DataRow r = drv.Row;
//組裝出前端要用的欄位
lst.Add(string.Format("{0}|{1}|{2}", r["key"], r["symbol"], r["cname"]));
if (lst.Count >= 10) break;
}
//每筆資料間以換行分隔
Response.Write(string.Join("\n", lst.ToArray()));
}
}
private DataTable getStockData()
{
#region 股票代號
string rawData = @"
1435 中福 C.F.C.Y.CORP.
1437 勤益 GTM
...省略...
8249 菱光 CSI
9912 偉聯 AIC";
#endregion
//如果資料量未多到誇張,將DataTable Cached住
string CACHE_KEY = "StkTable";
if (Cache[CACHE_KEY] == null)
{
DataTable t = new DataTable();
t.Columns.Add("Key", typeof(string));
t.Columns.Add("Symbol", typeof(string));
t.Columns.Add("CName", typeof(string));
t.Columns.Add("EName", typeof(string));
//測試時由字串取得資料,實務上會去查DB
StringReader sr = new StringReader(rawData);
string line = null;
while ((line = sr.ReadLine()) != null)
{
string[] p = line.Split('\t');
if (p.Length != 3) continue;
//分別以Symbol, CName, EName作Key
//輸入中英文及代號都可以查
t.Rows.Add(p[0], p[0], p[1], p[2]);
t.Rows.Add(p[1], p[0], p[1], p[2]);
t.Rows.Add(p[2], p[0], p[1], p[2]);
}
//放入Cache,保存兩小時
Cache.Add(CACHE_KEY, t, null, DateTime.Now.AddHours(2),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Normal, null);
}
return Cache[CACHE_KEY] as DataTable;
}
}
實作細節請大家看程式碼自行揣摩,應沒什麼深奧的學問在裡面。如果有什麼對程式架構或寫法方面的指教,歡迎提出來大家切磋。
想抓整包回去玩的朋友,請按這裡下載。