那一抹温暖的阳光,是我们永恒的向往。
www.webbar.cn

JavaScript 输入自动完成插件

JavaScript 输入自动完成插件

原理

这个插件主要用来方便用户在信息查询和处理时快捷、简单,其原理分析下:

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绑定前台页面输入标签,一个或者多个,代码如下:

 

/*
* 自动完成功能主函数(闭包)
*
* id:自动完成功能需要绑定的控件
*
* 版本:1.0
*/
function autoComplete(id) {
/****预留退路处理部分**begin**/
if (!document.getElementById) return false;
if (!document.createElement) return false;
if (!document.getElementsByTagName) return false;
/****预留退路处理部分**end**/

var me = this; //获取当前对象

/****变量初始化部分**begin**/
me.AutoCompleteControlID; //自动完成绑定控件客户端ID
me.handle = null; //自动完成绑定控件的对象
me.DivResult; //查询结果弹出层对象
me.currentIndex = -1; //当前选中的结果索引
me.LastIndex = -1; //上一条选中的结果索引
me.requestObj; //向服务器发送请求的对象
me.TableIndex = 0; //标记搜索结果的table的id,避免在同一个页面上出现两个相同id的table
me.OrgValue = “”; //记录用户当前输入的值
me.KeyType = true; //标记是上移(true)还是下移(false)
me.FocusInDiv = false; //标记当前焦点是否是搜索结果div
me.AllowEnterKeyFlag = false; //标记是否允许回车键接收事件
me.AllowClickFlag = false; //标记是否允许鼠标点击选择事件
me.AllowAutoComplete = true; //标记是否还需要继续实现自动完成功能(在用户传递参数有误的情况下使用,避免报错)
me.Requesttype = 1; //调用方式,使用请求页(1)\ajax函数(2)
me.RequestPageUrl = null; //请求页调用时的页面地址(包括参数)
me.ajaxCallBackFun = null; //ajax函数调用时的回调函数
me.AllowCallBackFun = null; //用户传递过来的接收回车或者鼠标点击事件的回调函数
//判断绑定控件的ID并赋值
if (id != null && typeof (id) != undefined) {
me.AutoCompleteControlID = id;
me.handle = document.getElementById(me.AutoCompleteControlID);
}

if (me.DivResult == null || typeof (me.DivResult) == “undefined”) {
me.DivResult = document.createElement(“div”);
var parent = document.getElementById(me.AutoCompleteControlID).parentElement;
if (typeof (parent) != “undefined”) {
parent.appendChild(me.DivResult);
}
}
/****变量初始化部分**end**/

}

二、初始化插件

选择插件的数据查询方式及各方式所需的参数,代码如下:

 

/*
* 初始化函数,负责初始化部分可选成员变量
* requestType:调用方式(1为请求页,2为ajax函数)
* pageUrl:如果是请求页的方式调用,则此参数必不能为空,若为ajax函数调用,则此参数为null
* ajaxCallBackFun:如果是ajax函数的方式调用,则此参数必不能为空,若为请求页方式调用,则此参数为null
* enterKeyFlag:标记是否允许回车事件
* mouseClickFlag:标记是否允许鼠标选择事件
* callBackFun:回调函数,与前两个参数配合使用,如果前两个参数有一个设置为true,则此处必须实现回调函数,否则为null
* tabIndex:绑定控件的编号,标记搜索结果table的id,以避免同页面的两个绑定控件的搜索结果id相同
*/
this.Init = function(requestType, pageUrl, ajaxCallBackFun, enterKeyFlag, mouseClickFlag, callBackFun, tabIndex) {
//初始化变量
me.Requesttype = requestType;
me.RequestPageUrl = pageUrl;
me.ajaxCallBackFun = ajaxCallBackFun;
me.AllowEnterKeyFlag = enterKeyFlag;
me.AllowClickFlag = mouseClickFlag;
me.TableIndex = tabIndex;
//判断请求方式
if (me.Requesttype == 1) {
me.ajaxCallBackFun = null;
if (me.RequestPageUrl == null) {
alert(“传递的参数有误,请求页的地址不能为null!”);
me.AllowAutoComplete = false;
}
}
else if (me.Requesttype == 2) {
me.RequestPageUrl = null;
if (me.ajaxCallBackFun == null) {
alert(“传递的参数有误,ajax回调函数不能为null!”);
me.AllowAutoComplete = false;
}
}
//判断标志位
if (!me.AllowEnterKeyFlag && !me.AllowClickFlag) {
callBackFun = null;
}
else {
if (callBackFun == null) {
alert(“传递的参数有误,回调函数不能为null!”);
me.AllowAutoComplete = false;
}
else {
me.AllowCallBackFun = callBackFun;
}
}
}

三、数据查询处理

根据初始化好的数据查询方式给后台发送数据查询请求,后台查询到数据后回馈给插件,这个过程的触发点是用户在输入标签中输入了查询关键字,实现该标签的键盘提起事件,代码如下:

 

//绑定控件的键盘弹起事件
document.getElementById(me.AutoCompleteControlID).onkeyup = function(evt) {
if (me.AllowAutoComplete) {
try {
evt = evt || window.event;
if (evt.keyCode != 40 && evt.keyCode != 38 && evt.keyCode != 39 && evt.keyCode != 37) {
me.OrgValue = me.handle.value;
}
else {//向下\向上
if (evt.keyCode == 38) me.KeyType = true;
else if (evt.keyCode == 40) me.KeyType = false;
}
me.Auto();
} catch (e) { }
}
}

通过实现Auto事件实现数据查询,代码如下:

 

this.Auto = function() {
var evt = evt || window.event;
//如果按下 向上, 向下 或 回车
if (evt.keyCode == 38 || evt.keyCode == 40 || evt.keyCode == 13) {
me.SelectItem();
}
//左右移动键
else if (evt.keyCode == 39 || evt.keyCode == 37) {
return;
}
else {
//恢复下拉选择项为 -1
currentIndex = -1;
//设置结果弹出层的样式
me.DivResult.style.position = “absolute”;
me.DivResult.style.top = me.handle.getBoundingClientRect().top + 19;
me.DivResult.style.left = me.handle.getBoundingClientRect().left – 2;
me.DivResult.style.width = me.handle.offsetWidth;
me.DivResult.style.height = 20;
me.DivResult.style.backgroundColor = “#ffffff”;

if (me.Requesttype == 1) {//页面请求

if (window.XMLHttpRequest) {
me.requestObj = new XMLHttpRequest();
if (me.requestObj.overrideMimeType)
me.requestObj.overrideMimeType(“text/xml”);
}
else if (window.ActiveXObject) {
try {
me.requestObj = new ActiveXObject(“Msxml2.XMLHTTP”);
}
catch (e) {
me.requestObj = new ActiveXObject(“Microsoft.XMLHTTP”);
}
}
if (me.requestObj == null)
return;
me.requestObj.onreadystatechange = me.ShowResult;
var strUrl = me.RequestPageUrl + “?InputValue=” + escape(me.handle.value) + “&TableIndex=” + me.TableIndex;
me.requestObj.open(“GET”, strUrl, true);
me.requestObj.send();
}
else {//ajax函数请求
try {
me.ajaxCallBackFun(me.handle.value, me.TableIndex, me.AjaxCallBack);
} catch (e) { }
}
}
}

Auto函数实现了数据查询这一过程,根据查询方式的不同,数据请求的方法也不同:

 1.如果是页面请求:插件根据初始化时提供的页面url内部进行ajax访问,并将响应的结果用方法me.ShowResult处理,该方法实现如下:

 

//搜索结果处理函数(页面请求调用时)
this.ShowResult = function() {
if (me.requestObj.readyState == 4) {
if (me.requestObj.status == 200)//ok
{
me.DivResult.innerHTML = me.AlynasisContent(me.requestObj.responseText);
//判断是否有搜索结果
var result = me.DivResult.getElementsByTagName(“td”);
if (result.length > 0) {
me.DivResult.style.height = result.length * 15;
me.DivResult.style.display = “”;
//给每个Td动态绑定事件(新建了一个闭包,用来传递参数,否则所有元素的一下三个鼠标事件的参数i会是相同的值)
for (var i = 0; i < result.length; i++) {
var bb = new BiBaoOnMouseResult(i, me);
result[i].onmouseover = bb.OnMouseOverEx;
result[i].onmouseout = bb.OnMouseOutEx;
result[i].onclick = bb.OnMouseClickEx;
}
}
else {
me.DivResult.style.display = “none”;
return;
}
me.requestObj = null; //销毁对象
}
else if (me.requestObj.status == 404) {
//alert(“请求的页面未找到!”);
me.DivResult.style.display = “none”;
me.requestObj = null; //销毁对象
return;
}
}
}

2.ajax函数请求:插件直接调用初始化时提供的外部ajax函数,并将结果处理函数me.AjaxCallBack作为最后一个参数传递到该ajax函数中,以便在数据查询完成时调用,该方法实现如下:

 

//搜索结果处理函数(ajax函数请求方式)
this.AjaxCallBack = function(response) {
if (response.error != null) {
return;
}
me.DivResult.innerHTML = me.AlynasisContent(response.value);
//判断是否有搜索结果
var result = me.DivResult.getElementsByTagName(“td”);
if (result.length > 0) {
me.DivResult.style.height = result.length * 15;
me.DivResult.style.display = “”;
//给每个Td动态绑定事件(新建了一个闭包,用来传递参数,否则所有元素的一下三个鼠标事件的参数i会是相同的值)
for (var i = 0; i < result.length; i++) {
var bb = new BiBaoOnMouseResult(i, me);
result[i].onmouseover = bb.OnMouseOverEx;
result[i].onmouseout = bb.OnMouseOutEx;
result[i].onclick = bb.OnMouseClickEx;
}
}
else {
me.DivResult.style.display = “none”;
return;
}
}

四、查询结果展现

上述两种数据查询代码中,都通过方法me.AlynasisContent来对查询结果进行解析,该函数用表格的方式展现该查询结果,每条一行,代码如下:

 

//解析搜索返回的结果
this.AlynasisContent = function(strObj) {
if (strObj == null || strObj == “”) {
return “”;
}

var itemList = strObj.split(“@|@”);
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%;’>”;
for (var i = 0; i < itemList.length; i++) {
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>”;
}
strResult += “</table>”;
return strResult;
}

至此,插件的流程全部完成,但还有很多细节功能,比如鼠标选择、键盘上下键选择、给查询结果中每条记录添加鼠标和键盘事件并响应等,全部代码将在后面给出,下面以.net开发为例来演示此插件的调用方法:

【用法1】请求aspx页面(“AutoComplete.aspx”),必须要实现页面,如果选择了接收回车键和鼠标选择事件,则必须要实现ReturnAutoComplete()函数。

 

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

【用法2】ajax方法请求,必须要实现CallAjaxFuntion函数,如果选择 了接收回车键和鼠标选择事件,则必须要实现ReturnAutoComplete()函数,下面ajax请求是通过ajaxpro来实现的,当然,可以根 据需要可以使用其他ajax方式调用。

 

var auto2 = new autoComplete(“text”);
auto2.Init(2, null, CallAjaxFuntion, false, true, ReturnAutoComplete, 1);
function CallAjaxFuntion(strTxtValue, resultTableIndex, ajaxCallBack) {

_Default.GetDataSource(strTxtValue, resultTableIndex, ajaxCallBack);

}

ReturnAutoComplete方法实现如下:

 

//接收回车或鼠标点击事件(returnValue:为选中的textbox的值)
function ReturnAutoComplete(returnValue) {
alert(returnValue);
//do something else
}

 

页面: 1 2

时间:2014-04-16
标签:

Comments are closed.

Search