把前段时间做的Auto Complete功能做了下整理 与各位分享
由于我们项目尽量避免使用AJAX,所以我们不得不重新写了套东西来实现Auto Complete。 还是感觉做成控件好一点。下面我来说下具体实现。
基本原理就是利用回发机制,实现ICallbackEventHandler接口来达到页面不刷新 但是能与后台交换数据的功能。
ASPX
<
html xmlns
=
"
http://www.w3.org/1999/xhtml
"
>
<
head runat
=
"
server
"
>
<
title
>
Audto Complete
</
title
>
<
script src
=
"
autoComplete.js
"
type
=
"
text/javascript
"
language
=
"
javascript
"
></
script
>
</
head
>
<
body
>
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
div
>
<
script
>
function GetServerMethod(controlID)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
var message = controlID+","+document.getElementById(controlID).value;
var context = controlID;
<%=Page.ClientScript.GetCallbackEventReference(this, "message", "ShowAutoCompleteList", "context")%>
}
</
script
>
<
asp:Label ID
=
"
lbl_Name
"
runat
=
"
server
"
Text
=
"
Product Name:
"
></
asp:Label
>
<
asp:TextBox ID
=
"
txt_Name
"
runat
=
"
server
"
onkeyup
=
"
GetServerMethod(this.id);
"
autocomplete
=
"
off
"
></
asp:TextBox
>
</
div
>
</
form
>
</
body
>
</
html
>
注意把TEXTBOX的autocomplete属性设为FALSE,不然会引起浏览器的自动填充功能。
我把对应要实现AutoComplete的控件ID和输入的值传到服务器端,message 保存ID和值,context保存ID,然后调用服务器方法。我们再来看下CS 文件
要实现接口 ICallbackEventHandler, 很简单
ICallbackEventHandler Members
#region ICallbackEventHandler Members
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string GetCallbackResult()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.RenderList(_eventArgument);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseCallbackEvent(string eventArgument)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
_eventArgument = eventArgument;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
我们来看看RenderList方法是怎么写的
/**/
/// <summary>
/// Fill the auto complete with datasource and argument passed from aspx.
/// </summary>
/// <param name="eventArgument">value passed from aspx</param>
/// <returns>a string contains all the html source used by auto complete</returns>
public
string
RenderList(
string
eventArgument)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
string controlID = eventArgument.Split(',')[0];
string controlValue = eventArgument.Split(',')[1];
if (controlValue == string.Empty)
return string.Empty;
StringBuilder strBuilder = new StringBuilder();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
for (int i = 0; i < _dataSource.Count; i++)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (_dataSource[i].ToString().StartsWith(controlValue, StringComparison.OrdinalIgnoreCase))
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
strBuilder.Append("<div οnclick=""ValueFill(this, '" + controlID + "')"";'>");
strBuilder.Append(_dataSource[i].ToString());
strBuilder.Append("</div>");
}
}
return strBuilder.ToString();
}
主要就是通过控件上传来的值到服务器端的数据源中做比较 符合的就拿出来 生成到一个DIV中 最终生成一个符合的列表。
![](https://i-blog.csdnimg.cn/blog_migrate/355a4c2d3c19a59428c42fc4e86421de.png)
下面是写JS和样式
function
ShowAutoCompleteList(retMessage, context)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
var autoComplete=document.getElementById('AutoComplete');
if(retMessage=='')
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Reset(); return;
}
autoComplete.className="AutoComplete";
autoComplete.style.display="block";
autoComplete.style.left=getX(document.getElementById(context))+"px";
autoComplete.style.top=getY(document.getElementById(context))+document.getElementById(context).offsetHeight+"px";
autoComplete.style.width=document.getElementById(context).offsetWidth+"px";
autoComplete.innerHTML=retMessage;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
function
ValueFill(obj,controlID)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
document.getElementById(controlID).value=obj.innerHTML;
Reset();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
function
Reset()
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
document.getElementById('AutoComplete').className="AutoCompleteHide";
document.getElementById('AutoComplete').innerHTML="";
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function
getX(elem)
{
var x = elem.offsetLeft;
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
while(elem = elem.offsetParent)
{
x = x + elem.offsetLeft;
}
return x;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function
getY(elem)
{
var y = elem.offsetTop;
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
while(elem = elem.offsetParent)
{
y = y + elem.offsetTop;
}
return y;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if
(document.addEventListener)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{document.addEventListener('click',Reset, false);}
else
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{document.attachEvent('onclick',Reset);}
/**/
/* AutoComplete Start */
.AutoComplete
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
}
{
float: left;
z-index: 1;
position: absolute;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-color: #D8D8D8;
border-right-color: #D8D8D8;
border-bottom-color: #D8D8D8;
border-left-color: #D8D8D8;
background-color: White;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
.AutoCompleteHide
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
}
{
position: absolute;
visibility: hidden;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
.AutoComplete div:hover
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
}
{
background-color: #00bbff;
cursor:default;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**/
/* AutoComplete End */
问题
其实没啥大的难度,利用接口+JS+样式。不过我这个auto complete还不是个控件,还有在出发回发事件上还有点小问题。
我是在 onkeyup的时候做的异步回发,这就是说在控件获得焦点,每次按键都会和服务器交互,这显然会加重服务器端压力,这以后要改的。
还有的就是没有加入上下按键选择功能,用起来有点不方便。
各位有啥好的建议也不妨介绍下 谢谢