作为web开发的一员,应该都不陌生,信息处理时,很多时候需要根据用户的输入实时反馈查询结果供其选择,这给了用户很好的人机交互体验,在各大门户网站上已经被使用的很成熟了,最近项目中用到此功能,网上有很多插件和样例,但用起来发现都多多少少与项目的需求有所出入,故自己写了一个,分享一下,希望能给你带来帮助,插件效果图如下:
原理
这个插件主要用来方便用户在信息查询和处理时快捷、简单,其原理分析下:
1. 信息处理需要前台和后台,前台有一个或者多个查询输入框(目前暂定为input标签)。
2. 用户在这些输入框中输入查询关键字时,系统根据用户实时的输入给页面后台发送数据查询请求。
3. 后台程序查询数据并排序,将最符合用户查询的记录(暂定为前10条)回传给前台插件。
4. 插件内部根据这些查询结果友好的展现出来给用户,用户选择展现出来的结果中某一条,该条记录关键字会自动补齐用户的输入。
功能
为了完成上述过程,这个插件需要帮用户做到以下一系列功能:
1. 能够根据标签id绑定一个或者多个输入标签,各标签的查询自定完成过程相互独立,互不影响。
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)。
接下来,根据实现原理编写插件:
一、绑定标签
插件根据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 }
二、初始化插件
选择插件的数据查询方式及各方式所需的参数,代码如下:
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 }
三、数据查询处理
根据初始化好的数据查询方式给后台发送数据查询请求,后台查询到数据后回馈给插件,这个过程的触发点是用户在输入标签中输入了查询关键字,实现该标签的键盘提起事件,代码如下:
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 }
四、查询结果展现
上述两种数据查询代码中,都通过方法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;100%;'>"; 9 for (var i = 0; i < itemList.length; i++) { 10 strResult += "<tr ReturnValue=" + itemList[i] + "><td height='15' nowrap><div style='" + (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;100%;'>"; 214 for (var i = 0; i < itemList.length; i++) { 215 strResult += "<tr ReturnValue=" + itemList[i] + "><td height='15' nowrap><div style='" + (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 }