UPDATE:修正了在FireFox下顯示的問題,重新copy CSS即可
寫完這個名字忽然覺得有點標題黨的嫌疑,但是又不知道什麼樣的名字比較合適,那就暫且這樣吧。
今天要講的東西比較簡單,其中會用到另外的一個jQuery控制項,是一個人員選擇輸入框。那到底是個什麼東西呢?
那好還是先來看最後的效果,有個直接的瞭解。
是不是和時下流行的SNS網站的選擇人員控制項很像?對比一下,哈哈是的,其實目的是差不多的。
其實還有很多這樣應用,如郵件系統中寄件者,在輸入時的自動補全,它是一個類似於Autocomplete的功能,但是又要比Autocomplete多那麼一些功能的外掛程式
基於這個情況,我所編寫的這個控制項時基於一個Autocomplete控制項的,它就是jQuery.autocomplete,它的官方網址是:http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/
大家可以通過訪問以下來擷取它的使用方法,資料和demo還是比較詳細,我這邊就不重複寫了。所以我們還是直接開始擴充的部分
第一我們還是先確定HTML
從html上分析autocomplete和選人控制項的所查的就是
1:外側的容器 2:選中的人員的那個小方塊
容器我們用Div就可以了,小方塊也比較簡單 ,來看一下,最外層是div包裹,然後是嵌套一個a標籤(為了方便以後做hover效果),在a標籤中是一個span放置文字,
input[type=hidden]來防止這個節點的資料,img就似乎刪除按鈕的載體,那控制項的載體又是什麼呢?其實從設計來說可以是個input的,但是我更偏向於div,在執行個體化的時候往div中動態添加一個input來附加autocomplete的屬性,如果反過來在input外包裹容器的話,在一些特殊情況下定位會是問題。
那html既然已經定義好了,接著就是CSS了,這個css其實很簡單,就是容器的邊框還有就是item的樣子而已,來看下代碼
.bbit-usbox{ border: solid 1px #3C7FB1; margin:20px; padding:2px; display:block; background-color:#f3fefe;}.bbit-usbox .bbit-usbox-item{ width:auto; margin-left:4px; margin-top:2px; background-color:#e0e5ee; border: solid 1px #ccd5e4; float:left; white-space : nowrap;}.bbit-usbox .bbit-usbox-item a{ color:#000; text-decoration:none; padding-left:2px;}.bbit-usbox .bbit-usbox-item a span{ }.bbit-usbox .bbit-usbox-del{ background:url("images/usbox/del.gif") no-repeat 50% 80%; width:10px; height:5px; cursor:pointer; border:none; vertical-align:middle; margin-left:2px;}.bbit-usbox-boxc { margin-left:4px; clear:left;}.bbit-usbox-box{}.bbit-usbox-boxc input{ background-color:#f3fefe; width:100%; height:17px; display:block; border:none; }
本例中只有使用一個圖片
第二 開始編寫Javascript
還是老規矩,先來個完整代碼,非常簡單只有不到70行代碼
; (function($) { if (!$.Autocompleter) { alert("請先引用jquery.autocomplete.js"); return; } $.fn.usbox = function(o) { var def = { urlOrData: "ResponseAutoComplete.ashx", width: "90%", //寬度 addItem: false, removeItem: false, clickItem: function() { }, completeOp: {} }; $.extend(def, o); var co = $.extend({ scroll: false, formatItem: function(row, i, max) { return row[0] + "[" + row[1] + "]"; } }, def.completeOp); var temp = "<div class='bbit-usbox-item'><a href='javascript:void(0);'><span>${text}</span><input type='hidden' value='${value}'/><img src='../Themes/Shared/images/s.gif' alt='點擊刪除' class='bbit-usbox-del'/></a></div>"; return this.each(function(e) { var me = $(this); var id = me.attr("id"); if (id == null || id == "") { id = "usbox_" + new Date().getTime(); } var inc = $("<div class='bbit-usbox-boxc'/>"); var input = $("<input type='text' id='" + id + "_inbox' class='bbit-usbox-box' />").appendTo(inc); me.addClass("bbit-usbox").width(def.width).append(inc); input.autocomplete(def.urlOrData, co).result(function(event, data, formatted) { $(this).val(""); additem(this, data); }); me.bind("addboxitem", function(e,data) { additem(input,data); }); function additem(inc, data) { var tp = $(temp.replace(/\$\{([\w]+)\}/g, function(s1, s2) { if (s2 == "text") { return data[0]; } else if (s2 == "value") { return data.join("|"); } else { return s1; } })); tp.click(def.clickItem).find("img.bbit-usbox-del").click(removeitem); $(inc).parent().before(tp); if (def.addItem) { def.addItem(data); } } function removeitem() { var p = $(this).prev() var v = p.val(); var arr = v.split("|"); if (def.removeItem) { def.removeItem(arr); } $(this).parent().parent().remove(); } return me; }); }; $.fn.addboxitem = function(op) { $(this).trigger("addboxitem", [op]); };})(jQuery)
接著我們來一步一步來分析我的實現,開始還是編寫jQuery控制項的“模板”,關於為什麼要這麼寫,請參考這篇的說明
; (function($) { if (!$.Autocompleter) { alert("請先引用jquery.autocomplete.js"); return; } $.fn.usbox = function(o) { }})(jQuery)
這次加了一個判斷,因為我們這個控制項是依賴於autocomplete的,如果你看了前兩篇,那麼就一定知道接著就是編寫預設參數
var def = { urlOrData:false,//必須!請求資料的url和或者直接是資料,格式參考autocomplete的說明 width: "90%", //寬度 addItem: false,//當從下拉選項中選擇一個人員後觸發的函數 removeItem: false,//當從已選擇的人員刪除一個人時觸發的函數 clickItem: function() { },//點擊人員小方塊時觸發的時間 completeOp: {}//autocomplete的參數,格式參考它自身的說明 };
參數也是比較簡單,添加和移除的兩個函數比較重要,在demo中會講到,autocomplete的參數因為太多,大家只有自己參考一下官方的說明, 預設不管也可以,因為我會給大家預設來一下.
$.extend(def, o);//這才是預設的Complete的參數 var co = $.extend({ scroll: false, formatItem: function(row, i, max) { return row[0] + "[" + row[1] + "]"; } }, def.completeOp);//定義小方塊的模板,其中s.gif是個空圖片,位置可根據實際情況進行調整 var temp = "${text}";
formatItem函數是下拉中顯示的格式 ,接著是產生HTML,註冊事件,詳細的步驟我已經注釋到代碼中了如下所示
return this.each(function(e) { var me = $(this); var id = me.attr("id"); //擷取唯一的ID if (id == null || id == "") { id = "usbox_" + new Date().getTime(); } //input的容器 var inc = $("<div class='bbit-usbox-boxc'/>"); //產生一個input用於附加autocomplete控制項 var input = $("<input type='text' id='" + id + "_inbox' class='bbit-usbox-box' />").appendTo(inc); //設定樣式,並把input添加到對象中 me.addClass("bbit-usbox").width(def.width).append(inc); //給input註冊autocomplete功能,並設定回呼函數 input.autocomplete(def.urlOrData, co).result(function(event, data, formatted) { $(this).val("");//選擇人員了則把輸入框自己清空 additem(this, data);//產生小方塊 }); //註冊一個自訂的事件,事件名addboxitem me.bind("addboxitem", function(e,data) { additem(input,data); }); function additem(inc, data) { //小方塊的模板替換成正確的值 var tp = $(temp.replace(/\$\{([\w]+)\}/g, function(s1, s2) { if (s2 == "text") { return data[0]; //返回的第一個值是displayname } else if (s2 == "value") { return data.join("|");//其他全部放到input[type=hidden]中 } else { return s1; } })); //觸發小放開的click事件,並且在內部尋找刪除按鈕,註冊點擊事件,jQuery的鏈式哦 tp.click(def.clickItem).find("img.bbit-usbox-del").click(removeitem); //把小方塊放到input之前! $(inc).parent().before(tp); if (def.addItem) { //如果additem存在則觸發 def.addItem(data); } } //移除的方法 function removeitem() { var p = $(this).prev()//擷取input[type=hidden],this指向delete img var v = p.val(); var arr = v.split("|"); //拼成一個數組 if (def.removeItem) {//觸發移除函數 def.removeItem(arr); } //小方塊移除本身 $(this).parent().parent().remove();// } return me; });
最後是公開一個函數來方便外面調用additem,如我有一個彈出介面可以一次選擇n個人回來,那麼就可以調用這個函數了
$.fn.addboxitem = function(op) { $(this).trigger("addboxitem", [op]);//想到我在之前註冊的自訂事件了嗎? };
至此我們的控制項其實已經分析完成了,但是為了讓大家更好的理解這個控制項,我把對應的伺服器端代碼也順便寫寫因為Demo是Asp.NET MVC的,那麼就以asp.net mvc 為例來講吧 先來看看Demo的調用代碼,urlOrData是個Action,additem和removeitem分別處理將選中的人員添加到指定的隱藏欄位或從中刪除,以便表單提交。
$(document).ready(function() { $("#usbox").usbox({ width: 430, urlOrData:"<%=Url.Action("QueryComplete")%>", addItem: function(data) { var t = $("#hdtext").val(); var v = $("#hdvalue").val(); var t1 = t != "" ? t.split(",") : []; var v1 = v != "" ? v.split(",") : []; t1.push(data[0]); v1.push(data[2]); $("#hdtext").val(t1.join(",")); $("#hdvalue").val(v1.join(",")); }, removeItem: function(data) { var t = $("#hdtext").val(); var v = $("#hdvalue").val(); var t1 = t.split(","); var v1 = v.split(","); var index = -1; for (var i = v1.length - 1; i >= 0; i--) { if (data[2] == v1[i]) { index = i; break; } } if (index > -1) { t1.splice(index, 1); v1.splice(index, 1); $("#hdtext").val(t1.join(",")); $("#hdvalue").val(v1.join(",")); } } }); var tempdata = ["假正經哥哥", "xuanye","001"]; $("#usbox").addboxitem(tempdata); });
HTML代碼
<div id="usbox" class="bbit-usbox"> </div><input id="hdtext" type="text"/><input id="hdvalue" type="text"/>輸入框在實際項目中可能是隱藏欄位,預設我加上了假正經哥哥
再來看看Action的代碼,預設接受兩個參數,一個是q,即input中的輸入框,一個是限制條數(預設是10,可通過修改complete的參數來改變)
public ContentResult QueryComplete(string q, int limit) { string ret = ""; if (q != "" && limit >0) { //根據關鍵字搜尋資料庫或緩衝,這個就比較簡單不深入了 List<Person> list=_respository.QueryCompletePerson(q, limit); if (list != null) { StringBuilder sb = new StringBuilder(); foreach (Person person in list) { //以|分割的資料格式,可以是多個,這裡是三個。當然也可以吧ID作為特殊的 sb.AppendLine(person.FullName + "|" + person.PY+"|"+person.ID); } ret = sb.ToString(); } } return Content(ret); }
本樣本的地址是:http://jscs.cloudapp.net/ControlsSample/usbox
另外抱怨一下:部署到window azure 真的是有點麻煩喲。。搞了幾次
最後 你的支援就是我繼續寫作的動力!
本文地址:http://www.cnblogs.com/xuanye/archive/2009/10/28/1591733.html
轉載請保留!