JavaScript 輸入自動完成插件

  做爲web開發的一員,應該都不陌生,信息處理時,不少時候須要根據用戶的輸入實時反饋查詢結果供其選擇,這給了用戶很好的人機交互體驗,在各大門戶網站上已經被使用的很成熟了,最近項目中用到此功能,網上有不少插件和樣例,但用起來發現都多多少少與項目的需求有所出入,故本身寫了一個,分享一下,但願能給你帶來幫助,插件效果圖以下:web

原理ajax

這個插件主要用來方便用戶在信息查詢和處理時快捷、簡單,其原理分析下服務器

1. 信息處理須要前臺和後臺,前臺有一個或者多個查詢輸入框(目前暫定爲input標籤)。閉包

2. 用戶在這些輸入框中輸入查詢關鍵字時,系統根據用戶實時的輸入給頁面後臺發送數據查詢請求。app

3. 後臺程序查詢數據並排序,將最符合用戶查詢的記錄(暫定爲前10條)回傳給前臺插件。ide

4. 插件內部根據這些查詢結果友好的展示出來給用戶,用戶選擇展示出來的結果中某一條,該條記錄關鍵字會自動補齊用戶的輸入。函數

功能網站

爲了完成上述過程,這個插件須要幫用戶作到如下一系列功能:this

1. 可以根據標籤id綁定一個或者多個輸入標籤,各標籤的查詢自定完成過程相互獨立,互不影響。url

2. 用戶沒有輸入或者輸入爲空格等特殊字符時,不進行查詢,以減小服務器的負擔。

3. 根據用戶的輸入,實時展示查詢結果,每次展示最符合的前10條記錄,用菜單的方式,每條記錄一行,結果列表浮動與輸入標籤的下方,寬度和標籤寬度一致。

4. 浮動的查詢結果能夠用鼠標選擇,也能夠用鍵盤中的上下移動鍵進行選擇,選擇完畢後該條記錄中的關鍵字將自動補齊輸入框內容;鼠標移動上去後選中項的顏色要發生變化,上下鍵選擇時能夠循環列表,並保留用戶輸入的值。

5. 光標移入輸入框時進行查詢,查詢結果浮動層和輸入標籤失去焦點時浮動層影藏。

實現

首先插件根據須要能夠綁定一個或者多個頁面輸入標籤,插件只需獲取標籤的id便可,綁定多個輸入標籤時重複該過程,並須要對標籤進行編號,以便插件動態生成浮動結果列表時標記id。其次根據開發時不一樣的需求,插件中實時的結果查詢支持兩種方式:一種是經過請求中間頁面獲取,二是經過ajax獲取。兩種方式的實現要求插件暴露出來的接口將不同:

1)經過請求中間頁面獲取:插件須要一個請求中間頁的地址(URL),是否對鼠標選擇添加處理事件的標記(true&false),是否對按鍵選擇添加處理事件標記(true&false),若是須要前兩個標記有一個爲true,則插件還須要一個處理事件的方法入口(ReturnAutoComplete)。

2)經過ajax獲取:插件須要一個獲取查詢結果的ajax方法入口(CallAjaxFuntion),是否對鼠標選擇添加處理事件標記(true&false),是否對按鍵選擇添加處理事件標記(true&false),若是須要前兩個標記有一個爲true,則插件還須要一個處理事件的方法入口(ReturnAutoComplete)。

接下來,根據實現原理編寫插件:

1、綁定標籤

插件根據id綁定前臺頁面輸入標籤,一個或者多個,代碼以下:

 1 /*
 2  *    自動完成功能主函數(閉包)
 3  *
 4  *  id:自動完成功能須要綁定的控件
 5  *
 6  *  版本:1.0
 7  */
 8  function autoComplete(id) {
 9     /****預留退路處理部分**begin**/
10     if (!document.getElementById) return false;
11     if (!document.createElement) return false;
12     if (!document.getElementsByTagName) return false; 
13     /****預留退路處理部分**end**/
14     
15     var me = this;            //獲取當前對象
16     
17     /****變量初始化部分**begin**/
18     me.AutoCompleteControlID; //自動完成綁定控件客戶端ID
19     me.handle = null;         //自動完成綁定控件的對象
20     me.DivResult;             //查詢結果彈出層對象
21     me.currentIndex = -1;     //當前選中的結果索引
22     me.LastIndex = -1;        //上一條選中的結果索引
23     me.requestObj;            //向服務器發送請求的對象
24     me.TableIndex = 0;        //標記搜索結果的table的id,避免在同一個頁面上出現兩個相同id的table
25     me.OrgValue = "";         //記錄用戶當前輸入的值
26     me.KeyType = true;        //標記是上移(true)仍是下移(false)
27     me.FocusInDiv = false;    //標記當前焦點是不是搜索結果div
28     me.AllowEnterKeyFlag = false;   //標記是否容許回車鍵接收事件
29     me.AllowClickFlag = false;      //標記是否容許鼠標點擊選擇事件
30     me.AllowAutoComplete = true;    //標記是否還須要繼續實現自動完成功能(在用戶傳遞參數有誤的狀況下使用,避免報錯)
31     me.Requesttype = 1;             //調用方式,使用請求頁(1)\ajax函數(2)
32     me.RequestPageUrl = null;       //請求頁調用時的頁面地址(包括參數)
33     me.ajaxCallBackFun = null;      //ajax函數調用時的回調函數
34     me.AllowCallBackFun = null;     //用戶傳遞過來的接收回車或者鼠標點擊事件的回調函數
35     //判斷綁定控件的ID並賦值
36     if (id != null && typeof (id) != undefined) {
37         me.AutoCompleteControlID = id;
38         me.handle = document.getElementById(me.AutoCompleteControlID);
39     }
40 
41     if (me.DivResult == null || typeof (me.DivResult) == "undefined") {
42         me.DivResult = document.createElement("div");
43         var parent = document.getElementById(me.AutoCompleteControlID).parentElement;
44         if (typeof (parent) != "undefined") {
45             parent.appendChild(me.DivResult);
46         }
47     }
48     /****變量初始化部分**end**/
49 
50 }

2、初始化插件

選擇插件的數據查詢方式及各方式所需的參數,代碼以下:

 1 /*
 2      *    初始化函數,負責初始化部分可選成員變量
 3      *  requestType:調用方式(1爲請求頁,2爲ajax函數)
 4      *  pageUrl:若是是請求頁的方式調用,則此參數必不能爲空,若爲ajax函數調用,則此參數爲null
 5      *  ajaxCallBackFun:若是是ajax函數的方式調用,則此參數必不能爲空,若爲請求頁方式調用,則此參數爲null
 6      *  enterKeyFlag:標記是否容許回車事件
 7      *  mouseClickFlag:標記是否容許鼠標選擇事件
 8      *  callBackFun:回調函數,與前兩個參數配合使用,若是前兩個參數有一個設置爲true,則此處必須實現回調函數,不然爲null
 9      *  tabIndex:綁定控件的編號,標記搜索結果table的id,以免同頁面的兩個綁定控件的搜索結果id相同
10      */
11     this.Init = function(requestType, pageUrl, ajaxCallBackFun, enterKeyFlag, mouseClickFlag, callBackFun, tabIndex) {
12         //初始化變量
13         me.Requesttype = requestType;
14         me.RequestPageUrl = pageUrl;
15         me.ajaxCallBackFun = ajaxCallBackFun;
16         me.AllowEnterKeyFlag = enterKeyFlag;
17         me.AllowClickFlag = mouseClickFlag;
18         me.TableIndex = tabIndex;
19         //判斷請求方式
20         if (me.Requesttype == 1) {
21             me.ajaxCallBackFun = null;
22             if (me.RequestPageUrl == null) {
23                 alert("傳遞的參數有誤,請求頁的地址不能爲null!");
24                 me.AllowAutoComplete = false;
25             }
26         }
27         else if (me.Requesttype == 2) {
28             me.RequestPageUrl = null;
29             if (me.ajaxCallBackFun == null) {
30                 alert("傳遞的參數有誤,ajax回調函數不能爲null!");
31                 me.AllowAutoComplete = false;
32             }
33         }
34         //判斷標誌位
35         if (!me.AllowEnterKeyFlag && !me.AllowClickFlag) {
36             callBackFun = null;
37         }
38         else {
39             if (callBackFun == null) {
40                 alert("傳遞的參數有誤,回調函數不能爲null!");
41                 me.AllowAutoComplete = false;
42             }
43             else {
44                 me.AllowCallBackFun = callBackFun;
45             }
46         }
47     }

3、數據查詢處理

根據初始化好的數據查詢方式給後臺發送數據查詢請求,後臺查詢到數據後回饋給插件,這個過程的觸發點是用戶在輸入標籤中輸入了查詢關鍵字,實現該標籤的鍵盤提起事件,代碼以下:

 1 //綁定控件的鍵盤彈起事件
 2     document.getElementById(me.AutoCompleteControlID).onkeyup = function(evt) {
 3         if (me.AllowAutoComplete) {
 4             try {
 5                 evt = evt || window.event;
 6                 if (evt.keyCode != 40 && evt.keyCode != 38 && evt.keyCode != 39 && evt.keyCode != 37) {
 7                     me.OrgValue = me.handle.value;
 8                 }
 9                 else {//向下\向上
10                     if (evt.keyCode == 38) me.KeyType = true;
11                     else if (evt.keyCode == 40) me.KeyType = false;
12                 }
13                 me.Auto();
14             } catch (e) { }
15         }
16     }

經過實現Auto事件實現數據查詢,代碼以下:

 1 this.Auto = function() {
 2         var evt = evt || window.event;
 3         //若是按下 向上, 向下 或 回車 
 4         if (evt.keyCode == 38 || evt.keyCode == 40 || evt.keyCode == 13) {
 5             me.SelectItem();
 6         }
 7         //左右移動鍵
 8         else if (evt.keyCode == 39 || evt.keyCode == 37) {
 9             return;
10         }
11         else {
12             //恢復下拉選擇項爲 -1
13             currentIndex = -1;
14             //設置結果彈出層的樣式
15             me.DivResult.style.position = "absolute";
16             me.DivResult.style.top = me.handle.getBoundingClientRect().top + 19;
17             me.DivResult.style.left = me.handle.getBoundingClientRect().left - 2;
18             me.DivResult.style.width = me.handle.offsetWidth;
19             me.DivResult.style.height = 20;
20             me.DivResult.style.backgroundColor = "#ffffff";
21 
22             if (me.Requesttype == 1) {//頁面請求
23 
24                 if (window.XMLHttpRequest) {
25                     me.requestObj = new XMLHttpRequest();
26                     if (me.requestObj.overrideMimeType)
27                         me.requestObj.overrideMimeType("text/xml");
28                 }
29                 else if (window.ActiveXObject) {
30                     try {
31                         me.requestObj = new ActiveXObject("Msxml2.XMLHTTP");
32                     }
33                     catch (e) {
34                         me.requestObj = new ActiveXObject("Microsoft.XMLHTTP");
35                     }
36                 }
37                 if (me.requestObj == null)
38                     return;
39                 me.requestObj.onreadystatechange = me.ShowResult;
40                 var strUrl = me.RequestPageUrl + "?InputValue=" + escape(me.handle.value) + "&TableIndex=" + me.TableIndex;
41                 me.requestObj.open("GET", strUrl, true);
42                 me.requestObj.send();
43             }
44             else {//ajax函數請求
45                 try {
46                     me.ajaxCallBackFun(me.handle.value, me.TableIndex, me.AjaxCallBack);
47                 } catch (e) { }
48             }
49         }
50     }

 Auto函數實現了數據查詢這一過程,根據查詢方式的不一樣,數據請求的方法也不一樣:

 1.若是是頁面請求:插件根據初始化時提供的頁面url內部進行ajax訪問,並將響應的結果用方法me.ShowResult處理,該方法實現以下:

 1 //搜索結果處理函數(頁面請求調用時)
 2     this.ShowResult = function() {
 3         if (me.requestObj.readyState == 4) {
 4             if (me.requestObj.status == 200)//ok
 5             {
 6                 me.DivResult.innerHTML = me.AlynasisContent(me.requestObj.responseText);  7                 //判斷是否有搜索結果
 8                 var result = me.DivResult.getElementsByTagName("td");
 9                 if (result.length > 0) {
10                     me.DivResult.style.height = result.length * 15;
11                     me.DivResult.style.display = "";
12                     //給每一個Td動態綁定事件(新建了一個閉包,用來傳遞參數,不然全部元素的一下三個鼠標事件的參數i會是相同的值)
13                     for (var i = 0; i < result.length; i++) {
14                         var bb = new BiBaoOnMouseResult(i, me);
15                         result[i].onmouseover = bb.OnMouseOverEx;
16                         result[i].onmouseout = bb.OnMouseOutEx;
17                         result[i].onclick = bb.OnMouseClickEx;
18                     }
19                 }
20                 else {
21                     me.DivResult.style.display = "none";
22                     return;
23                 }
24                 me.requestObj = null; //銷燬對象
25             }
26             else if (me.requestObj.status == 404) {
27                 //alert("請求的頁面未找到!");
28                 me.DivResult.style.display = "none";
29                 me.requestObj = null; //銷燬對象
30                 return;
31             }
32         }
33     }

2.ajax函數請求:插件直接調用初始化時提供的外部ajax函數,並將結果處理函數me.AjaxCallBack做爲最後一個參數傳遞到該ajax函數中,以便在數據查詢完成時調用,該方法實現以下:

 1 //搜索結果處理函數(ajax函數請求方式)
 2     this.AjaxCallBack = function(response) {
 3         if (response.error != null) {
 4             return;
 5         }
 6         me.DivResult.innerHTML = me.AlynasisContent(response.value);  7         //判斷是否有搜索結果
 8         var result = me.DivResult.getElementsByTagName("td");
 9         if (result.length > 0) {
10             me.DivResult.style.height = result.length * 15;
11             me.DivResult.style.display = "";
12             //給每一個Td動態綁定事件(新建了一個閉包,用來傳遞參數,不然全部元素的一下三個鼠標事件的參數i會是相同的值)
13             for (var i = 0; i < result.length; i++) {
14                 var bb = new BiBaoOnMouseResult(i, me);
15                 result[i].onmouseover = bb.OnMouseOverEx;
16                 result[i].onmouseout = bb.OnMouseOutEx;
17                 result[i].onclick = bb.OnMouseClickEx;
18             }
19         }
20         else {
21             me.DivResult.style.display = "none";
22             return;
23         }
24     }

4、查詢結果展示

上述兩種數據查詢代碼中,都經過方法me.AlynasisContent來對查詢結果進行解析,該函數用表格的方式展示該查詢結果,每條一行,代碼以下:

 1 //解析搜索返回的結果
 2     this.AlynasisContent = function(strObj) {
 3         if (strObj == null || strObj == "") {
 4             return "";
 5         }
 6 
 7         var itemList = strObj.split("@|@");
 8         var strResult = "<table cellSpacing='0' cellPadding='0' align='center' border='0' id='Tmp_AutoComplete_tblResult_" + me.TableIndex + "' style='padding-left:5;padding-right:5; background-color:#FFFFFF;border:1px solid #999999;text-align:left;width:100%;'>";
 9         for (var i = 0; i < itemList.length; i++) {
10             strResult += "<tr ReturnValue=" + itemList[i] + "><td height='15' nowrap><div style='width:" + (me.handle.offsetWidth - 12) + ";overflow:hidden;text-overflow:ellipsis;white-space:nowrap;'>" + itemList[i] + "<div></td></tr>";
11         }
12         strResult += "</table>";
13         return strResult;
14     }

 

 

至此,插件的流程所有完成,但還有不少細節功能,好比鼠標選擇、鍵盤上下鍵選擇、給查詢結果中每條記錄添加鼠標和鍵盤事件並響應等,所有代碼將在後面給出,下面以.net開發爲例來演示此插件的調用方法:

【用法1】請求aspx頁面(「AutoComplete.aspx」),必需要實現頁面,若是選擇了接收回車鍵和鼠標選擇事件,則必需要實現ReturnAutoComplete()函數。

1 var auto1 = new autoComplete("txt");
2 auto1.Init(1, "AutoComplete.aspx", null, true, false, ReturnAutoComplete, 1);

【用法2】ajax方法請求,必需要實現CallAjaxFuntion函數,若是選擇了接收回車鍵和鼠標選擇事件,則必需要實現ReturnAutoComplete()函數,下面ajax請求是經過ajaxpro來實現的,固然,能夠根據須要可使用其餘ajax方式調用。

1 var auto2 = new autoComplete("text");
2 auto2.Init(2, null, CallAjaxFuntion, false, true, ReturnAutoComplete, 1);
3 function CallAjaxFuntion(strTxtValue, resultTableIndex, ajaxCallBack) {
4     _Default.GetDataSource(strTxtValue, resultTableIndex, ajaxCallBack);
5 }

ReturnAutoComplete方法實現以下:

1 //接收回車或鼠標點擊事件(returnValue:爲選中的textbox的值)
2 function ReturnAutoComplete(returnValue) {
3     alert(returnValue);
4     //do something else
5 }

 

 

最後,插件源碼以下(下載文件請點擊Download):

  1 /*
  2  *    自動完成功能主函數(閉包)
  3  *
  4  *  id:自動完成功能須要綁定的控件
  5  *
  6  *  版本:1.0
  7  */
  8  function autoComplete(id) {
  9     /****預留退路處理部分**begin**/
 10     if (!document.getElementById) return false;
 11     if (!document.createElement) return false;
 12     if (!document.getElementsByTagName) return false; 
 13     /****預留退路處理部分**end**/
 14     
 15     var me = this;            //獲取當前對象
 16     
 17     /****變量初始化部分**begin**/
 18     me.AutoCompleteControlID; //自動完成綁定控件客戶端ID
 19     me.handle = null;         //自動完成綁定控件的對象
 20     me.DivResult;             //查詢結果彈出層對象
 21     me.currentIndex = -1;     //當前選中的結果索引
 22     me.LastIndex = -1;        //上一條選中的結果索引
 23     me.requestObj;            //向服務器發送請求的對象
 24     me.TableIndex = 0;        //標記搜索結果的table的id,避免在同一個頁面上出現兩個相同id的table
 25     me.OrgValue = "";         //記錄用戶當前輸入的值
 26     me.KeyType = true;        //標記是上移(true)仍是下移(false)
 27     me.FocusInDiv = false;    //標記當前焦點是不是搜索結果div
 28     me.AllowEnterKeyFlag = false;   //標記是否容許回車鍵接收事件
 29     me.AllowClickFlag = false;      //標記是否容許鼠標點擊選擇事件
 30     me.AllowAutoComplete = true;    //標記是否還須要繼續實現自動完成功能(在用戶傳遞參數有誤的狀況下使用,避免報錯)
 31     me.Requesttype = 1;             //調用方式,使用請求頁(1)\ajax函數(2)
 32     me.RequestPageUrl = null;       //請求頁調用時的頁面地址(包括參數)
 33     me.ajaxCallBackFun = null;      //ajax函數調用時的回調函數
 34     me.AllowCallBackFun = null;     //用戶傳遞過來的接收回車或者鼠標點擊事件的回調函數
 35     //判斷綁定控件的ID並賦值
 36     if (id != null && typeof (id) != undefined) {
 37         me.AutoCompleteControlID = id;
 38         me.handle = document.getElementById(me.AutoCompleteControlID);
 39     }
 40 
 41     if (me.DivResult == null || typeof (me.DivResult) == "undefined") {
 42         me.DivResult = document.createElement("div");
 43         var parent = document.getElementById(me.AutoCompleteControlID).parentElement;
 44         if (typeof (parent) != "undefined") {
 45             parent.appendChild(me.DivResult);
 46         }
 47     }
 48     /****變量初始化部分**end**/
 49 
 50 
 51     /*
 52      *    初始化函數,負責初始化部分可選成員變量
 53      *  requestType:調用方式(1爲請求頁,2爲ajax函數)
 54      *  pageUrl:若是是請求頁的方式調用,則此參數必不能爲空,若爲ajax函數調用,則此參數爲null
 55      *  ajaxCallBackFun:若是是ajax函數的方式調用,則此參數必不能爲空,若爲請求頁方式調用,則此參數爲null
 56      *  enterKeyFlag:標記是否容許回車事件
 57      *  mouseClickFlag:標記是否容許鼠標選擇事件
 58      *  callBackFun:回調函數,與前兩個參數配合使用,若是前兩個參數有一個設置爲true,則此處必須實現回調函數,不然爲null
 59      *  tabIndex:綁定控件的編號,標記搜索結果table的id,以免同頁面的兩個綁定控件的搜索結果id相同
 60      */
 61     this.Init = function(requestType, pageUrl, ajaxCallBackFun, enterKeyFlag, mouseClickFlag, callBackFun, tabIndex) {
 62         //初始化變量
 63         me.Requesttype = requestType;
 64         me.RequestPageUrl = pageUrl;
 65         me.ajaxCallBackFun = ajaxCallBackFun;
 66         me.AllowEnterKeyFlag = enterKeyFlag;
 67         me.AllowClickFlag = mouseClickFlag;
 68         me.TableIndex = tabIndex;
 69         //判斷請求方式
 70         if (me.Requesttype == 1) {
 71             me.ajaxCallBackFun = null;
 72             if (me.RequestPageUrl == null) {
 73                 alert("傳遞的參數有誤,請求頁的地址不能爲null!");
 74                 me.AllowAutoComplete = false;
 75             }
 76         }
 77         else if (me.Requesttype == 2) {
 78             me.RequestPageUrl = null;
 79             if (me.ajaxCallBackFun == null) {
 80                 alert("傳遞的參數有誤,ajax回調函數不能爲null!");
 81                 me.AllowAutoComplete = false;
 82             }
 83         }
 84         //判斷標誌位
 85         if (!me.AllowEnterKeyFlag && !me.AllowClickFlag) {
 86             callBackFun = null;
 87         }
 88         else {
 89             if (callBackFun == null) {
 90                 alert("傳遞的參數有誤,回調函數不能爲null!");
 91                 me.AllowAutoComplete = false;
 92             }
 93             else {
 94                 me.AllowCallBackFun = callBackFun;
 95             }
 96         }
 97     }
 98 
 99     this.Auto = function() {
100         var evt = evt || window.event;
101         //若是按下 向上, 向下 或 回車 
102         if (evt.keyCode == 38 || evt.keyCode == 40 || evt.keyCode == 13) {
103             me.SelectItem();
104         }
105         //左右移動鍵
106         else if (evt.keyCode == 39 || evt.keyCode == 37) {
107             return;
108         }
109         else {
110             //恢復下拉選擇項爲 -1
111             currentIndex = -1;
112             //設置結果彈出層的樣式
113             me.DivResult.style.position = "absolute";
114             me.DivResult.style.top = me.handle.getBoundingClientRect().top + 19;
115             me.DivResult.style.left = me.handle.getBoundingClientRect().left - 2;
116             me.DivResult.style.width = me.handle.offsetWidth;
117             me.DivResult.style.height = 20;
118             me.DivResult.style.backgroundColor = "#ffffff";
119 
120             if (me.Requesttype == 1) {//頁面請求
121 
122                 if (window.XMLHttpRequest) {
123                     me.requestObj = new XMLHttpRequest();
124                     if (me.requestObj.overrideMimeType)
125                         me.requestObj.overrideMimeType("text/xml");
126                 }
127                 else if (window.ActiveXObject) {
128                     try {
129                         me.requestObj = new ActiveXObject("Msxml2.XMLHTTP");
130                     }
131                     catch (e) {
132                         me.requestObj = new ActiveXObject("Microsoft.XMLHTTP");
133                     }
134                 }
135                 if (me.requestObj == null)
136                     return;
137                 me.requestObj.onreadystatechange = me.ShowResult;
138                 var strUrl = me.RequestPageUrl + "?InputValue=" + escape(me.handle.value) + "&TableIndex=" + me.TableIndex;
139                 me.requestObj.open("GET", strUrl, true);
140                 me.requestObj.send();
141             }
142             else {//ajax函數請求
143                 try {
144                     me.ajaxCallBackFun(me.handle.value, me.TableIndex, me.AjaxCallBack);
145                 } catch (e) { }
146             }
147         }
148     }
149     //搜索結果處理函數(ajax函數請求方式)
150     this.AjaxCallBack = function(response) {
151         if (response.error != null) {
152             return;
153         }
154         me.DivResult.innerHTML = me.AlynasisContent(response.value);
155         //判斷是否有搜索結果
156         var result = me.DivResult.getElementsByTagName("td");
157         if (result.length > 0) {
158             me.DivResult.style.height = result.length * 15;
159             me.DivResult.style.display = "";
160             //給每一個Td動態綁定事件(新建了一個閉包,用來傳遞參數,不然全部元素的一下三個鼠標事件的參數i會是相同的值)
161             for (var i = 0; i < result.length; i++) {
162                 var bb = new BiBaoOnMouseResult(i, me);
163                 result[i].onmouseover = bb.OnMouseOverEx;
164                 result[i].onmouseout = bb.OnMouseOutEx;
165                 result[i].onclick = bb.OnMouseClickEx;
166             }
167         }
168         else {
169             me.DivResult.style.display = "none";
170             return;
171         }
172     }
173     //搜索結果處理函數(頁面請求調用時)
174     this.ShowResult = function() {
175         if (me.requestObj.readyState == 4) {
176             if (me.requestObj.status == 200)//ok
177             {
178                 me.DivResult.innerHTML = me.AlynasisContent(me.requestObj.responseText);
179                 //判斷是否有搜索結果
180                 var result = me.DivResult.getElementsByTagName("td");
181                 if (result.length > 0) {
182                     me.DivResult.style.height = result.length * 15;
183                     me.DivResult.style.display = "";
184                     //給每一個Td動態綁定事件(新建了一個閉包,用來傳遞參數,不然全部元素的一下三個鼠標事件的參數i會是相同的值)
185                     for (var i = 0; i < result.length; i++) {
186                         var bb = new BiBaoOnMouseResult(i, me);
187                         result[i].onmouseover = bb.OnMouseOverEx;
188                         result[i].onmouseout = bb.OnMouseOutEx;
189                         result[i].onclick = bb.OnMouseClickEx;
190                     }
191                 }
192                 else {
193                     me.DivResult.style.display = "none";
194                     return;
195                 }
196                 me.requestObj = null; //銷燬對象
197             }
198             else if (me.requestObj.status == 404) {
199                 //alert("請求的頁面未找到!");
200                 me.DivResult.style.display = "none";
201                 me.requestObj = null; //銷燬對象
202                 return;
203             }
204         }
205     }
206     //解析搜索返回的結果
207     this.AlynasisContent = function(strObj) {
208         if (strObj == null || strObj == "") {
209             return "";
210         }
211 
212         var itemList = strObj.split("@|@");
213         var strResult = "<table cellSpacing='0' cellPadding='0' align='center' border='0' id='Tmp_AutoComplete_tblResult_" + me.TableIndex + "' style='padding-left:5;padding-right:5; background-color:#FFFFFF;border:1px solid #999999;text-align:left;width:100%;'>";
214         for (var i = 0; i < itemList.length; i++) {
215             strResult += "<tr ReturnValue=" + itemList[i] + "><td height='15' nowrap><div style='width:" + (me.handle.offsetWidth - 12) + ";overflow:hidden;text-overflow:ellipsis;white-space:nowrap;'>" + itemList[i] + "<div></td></tr>";
216         }
217         strResult += "</table>";
218         return strResult;
219     }
220     //移動上下鍵選擇搜索結果選項事件
221     this.SelectItem = function() {
222         //結果 
223         var result = document.getElementById("Tmp_AutoComplete_tblResult_" + me.TableIndex);
224         if (!result)
225             return;
226         if (result.rows[me.LastIndex] != null) {
227             result.rows[me.LastIndex].style.backgroundColor = "#FFFFFF";
228             result.rows[me.LastIndex].style.color = "#000000";
229         }
230         var maxRow = result.rows.length;
231         //向上
232         if (event.keyCode == 38 && me.currentIndex >= 0) {
233             me.currentIndex--;
234             if (me.currentIndex == -1) {
235                 me.handle.value = me.OrgValue;
236             }
237             else {
238                 me.handle.value = result.rows[me.currentIndex].ReturnValue;
239             }
240         }
241         //向下
242         if (event.keyCode == 40 && me.currentIndex < maxRow) {
243             me.currentIndex++;
244             me.handle.value = result.rows[me.currentIndex].ReturnValue;
245         }
246         //回車 
247         if (event.keyCode == 13) {
248             me.Select();
249             me.InitItem();
250             return false;
251         }
252         if (result.rows[me.currentIndex] != undefined) {
253             //選中顏色
254             result.rows[me.currentIndex].style.backgroundColor = "gray"; //"#3161CE";
255             result.rows[me.currentIndex].style.color = "#FFFFFF";
256         }
257         me.LastIndex = me.currentIndex;
258         
259         if (!me.KeyType) {
260 
261             if ((me.currentIndex + 1) >= maxRow) {//若是達到最大值,則循環(向下)
262                 me.currentIndex++;
263                 if (me.currentIndex == (maxRow + 1)) me.currentIndex = -1;
264                 if (me.currentIndex == -1) {
265                     me.handle.value = me.OrgValue;
266                 }
267             }
268         }
269         else {
270             if (me.currentIndex == -1) me.currentIndex = maxRow; //若是達到最小值,則循環(向上)
271         }
272     }
273     
274     //回車選擇事件
275     this.Select = function() {
276         var result = document.getElementById("Tmp_AutoComplete_tblResult_" + me.TableIndex);
277         if (!result || result.rows.length <= 0)
278             return;
279         //取出選中的值
280         var ReturnValue = "";
281         if (me.currentIndex < 0)//直接取輸入框中的值
282             ReturnValue = me.handle.value;
283         else                    //取用戶選中的值
284             ReturnValue = result.rows[me.currentIndex].ReturnValue;
285         //自動完成功能出口,向主程序發送值信息
286         if (ReturnValue != undefined) {
287             me.DivResult.style.display = "none";
288             //自動完成處理事件--由用戶本身完成實現
289             if (me.AllowEnterKeyFlag)
290                 me.AllowCallBackFun(ReturnValue);
291         }
292     }
293     
294     this.Hide = function() {
295         me.DivResult.style.display = "none";
296         me.currentIndex = -1;
297     }
298     this.InitItem = function() {
299         me.DivResult.style.display = "none";
300         me.DivResult.innerHTML = "";
301         me.currentIndex = -1;
302     }
303     //搜索結果的鼠標事件
304     this.OnTdMouseOver = function(i) {
305         if (me.AllowAutoComplete) {
306             me.currentIndex = i;
307             var result = document.getElementById("Tmp_AutoComplete_tblResult_" + me.TableIndex);
308             result.rows[me.currentIndex].style.cursor = "point";
309             if (!result || result.rows.length <= 0)
310                 return;
311             //取消以前選中項的顏色
312             if (result.rows[me.LastIndex] != null) {
313                 result.rows[me.LastIndex].style.backgroundColor = "#FFFFFF";
314                 result.rows[me.LastIndex].style.color = "#000000";
315             }
316             //改變選中項的顏色
317             if (result.rows[me.currentIndex] != undefined) {
318                 result.rows[me.currentIndex].style.backgroundColor = "gray"; //"#3161CE";
319                 result.rows[me.currentIndex].style.color = "#FFFFFF";
320             }
321             me.LastIndex = me.currentIndex;
322         }
323     }
324     this.OnTdMouseOut = function(i) {
325         if (me.AllowAutoComplete) {
326             var result = document.getElementById("Tmp_AutoComplete_tblResult_" + me.TableIndex);
327             if (!result || result.rows.length <= 0)
328                 return;
329             if (result.rows[me.currentIndex] != undefined) {
330                 result.rows[me.currentIndex].style.backgroundColor = "#FFFFFF";
331                 result.rows[me.currentIndex].style.color = "#000000";
332             }
333         }
334     }
335     this.OnTdMouseClick = function(i) {
336         if (me.AllowAutoComplete) {
337             var evt = fixEvent(window.event);
338             var result = document.getElementById("Tmp_AutoComplete_tblResult_" + me.TableIndex);
339             if (!result || result.rows.length <= 0)
340                 return;
341             //給輸入框賦值
342             var ReturnValue = result.rows[me.currentIndex].ReturnValue;
343             me.handle.value = ReturnValue;
344             //隱藏搜索結果
345             me.Hide();
346             //自動完成處理事件--由用戶本身完成實現
347             if (me.AllowClickFlag)
348                 me.AllowCallBackFun(ReturnValue);
349         }
350     }
351     //彈出層的鼠標移入/出事件
352     me.DivResult.onmouseout = function() {
353         if (me.AllowAutoComplete) {
354             me.currentIndex = -1;
355             me.FocusInDiv = false;
356         }
357     }
358     me.DivResult.onmouseover = function() {
359         if (me.AllowAutoComplete) {
360             me.FocusInDiv = true;
361         }
362     }
363     //綁定控件的點擊事件
364     document.getElementById(me.AutoCompleteControlID).onclick = function() {
365         if (me.AllowAutoComplete) {
366             try {
367                 if (me.handle.value != "") {
368                     me.Auto();
369                 }
370                 me.currentIndex = -1; //還原當前索引
371             } catch (e) { }
372         }
373     }
374     //綁定控件的鍵盤彈起事件
375     document.getElementById(me.AutoCompleteControlID).onkeyup = function(evt) {
376         if (me.AllowAutoComplete) {
377             try {
378                 evt = evt || window.event;
379                 if (evt.keyCode != 40 && evt.keyCode != 38 && evt.keyCode != 39 && evt.keyCode != 37) {
380                     me.OrgValue = me.handle.value;
381                 }
382                 else {//向下\向上
383                     if (evt.keyCode == 38) me.KeyType = true;
384                     else if (evt.keyCode == 40) me.KeyType = false;
385                 }
386                 me.Auto();
387             } catch (e) { }
388         }
389     }
390     //綁定控件的鍵盤按下事件
391     document.getElementById(me.AutoCompleteControlID).onkeydown = function() {
392         if (me.AllowAutoComplete) {
393             if (event.keyCode == 13) {//回車
394                 try {
395                     me.Select()
396                     me.InitItem();
397                 } catch (e) { }
398             } 
399         }
400     }
401     //綁定控件的鼠標通過事件
402     document.getElementById(me.AutoCompleteControlID).onmouseover = function() {
403         if (me.AllowAutoComplete) {
404             me.currentIndex = -1;
405         }
406     }
407     //當綁定控件失去焦點時,隱藏彈出層
408     document.getElementById(me.AutoCompleteControlID).onblur = function() {
409         if (me.AllowAutoComplete) {
410             if (!me.FocusInDiv) {
411                 me.Hide();
412             }
413         } 
414     }
415 }
416 
417 
418 /*
419 * 新建一個閉包,用於實現鼠標點擊搜索結果時的事件,以解決經過訓練傳遞的參數一直是最後一個索引的問題    
420 *
421 * writter:zhangyu 2012-01-03
422 */
423 function BiBaoOnMouseResult(i, me) {
424     this.OnMouseClickEx = function() {
425         me.OnTdMouseClick(i);
426     };
427     this.OnMouseOverEx = function() {
428         me.OnTdMouseOver(i);
429     };
430     this.OnMouseOutEx = function() {
431         me.OnTdMouseOut(i);
432     };
433 }
View Code
相關文章
相關標籤/搜索