• JavaScript 输入自动完成插件


      作为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 }
    View Code
  • 相关阅读:
    @responseBody注解的使用
    springmvc下的省市县三级联动
    select 动态添加option函数
    清空select标签中option选项的4种不同方式
    javascript删除option选项的多种方法总结
    js如何获取select下拉框的value以及文本内容
    如何设置select下拉禁止选择
    java.sql.SQLSyntaxErrorException: ORA-00911: 无效字符
    转:通过他人完成任务的艺术
    ***周鸿祎谈创业:很多程序员高智商 但我一看就知道他们不会成功
  • 原文地址:https://www.cnblogs.com/freshfish/p/3431609.html
Copyright © 2020-2023  润新知