曾经在2006年初项目中使用的一个小例子。今天听项目组里人说这个有问题,所以拿出来修改了一下,突然想到很久没有发表文章了,所以偷懒一次。请勿扔砖头。
故事是分五步地:(最近说话爱用故事与其助词开头)
Step one:
window.onload = function(){
var elemSpan = document.createElement("span");
elemSpan.id = "spanOutput";
elemSpan.className = "spanTextDropdown";
document.body.appendChild(elemSpan);
//大家请注意这个setproperties 在step two里:js的面向对象就这样理解。
document.form1.txtCompany.obj =
SetProperties(document.form1.txtCompany,
document.form1.txtUserValue,'AjaxServer.aspx',
true,true,true,true,"",false,null);
}
Step two:
<asp:TextBox ID="txtCompany" runat="server" Width="180px" autocomplete="off"></asp:TextBox><input id="hidden1" type="hidden" name="txtUserValue"/>
Step three:
function SetProperties(xElem,xHidden,xserverCode,
xignoreCase,xmatchAnywhere,xmatchTextBoxWidth,
xshowNoMatchMessage,xnoMatchingDataMessage,xuseTimeout,
xtheVisibleTime){
//debugger;
var props={
elem: xElem,
hidden: xHidden,
serverCode: xserverCode,
regExFlags: ( (xignoreCase) ? "i" : "" ),
regExAny: ( (xmatchAnywhere) ? "" : "^" ),
matchAnywhere: xmatchAnywhere,
matchTextBoxWidth: xmatchTextBoxWidth,
theVisibleTime: xtheVisibleTime,
showNoMatchMessage: xshowNoMatchMessage,
noMatchingDataMessage: xnoMatchingDataMessage,
useTimeout: xuseTimeout
};
AddHandler(xElem);
return props;
}
//other browser
var isOpera=(navigator.userAgent.toLowerCase().indexOf("opera")!= -1);
function AddHandler(objText){
objText.onkeyup = GiveOptions;
objText.onblur = function(){
if(this.obj.useTimeout)StartTimeout();
}
if(isOpera)objText.onkeypress = GiveOptions;
}
//all
var arrOptions = new Array();
var strLastValue = "";
var bMadeRequest;
var theTextBox;
var objLastActive;
var currentValueSelected = -1;
var bNoResults = false;
var isTiming = false;
//keydown event
function GiveOptions(e){
var intKey = -1;
if(window.event){
intKey = event.keyCode;
theTextBox = event.srcElement;
}
else{
intKey = e.which;
theTextBox = e.target;
}
if(theTextBox.obj.useTimeout){
if(isTiming)EraseTimeout();
StartTimeout();
}
if(theTextBox.value.length == 0 && !isOpera){
arrOptions = new Array();
HideTheBox();
strLastValue = "";
return false;
}
if(objLastActive == theTextBox){
if(intKey == 13){
GrabHighlighted();
theTextBox.blur();
return false;
}
else if(intKey == 38){
MoveHighlight(-1);
return false;
}
else if(intKey == 40){
MoveHighlight(1);
return false;
}
else{}
}
if(objLastActive != theTextBox ||
theTextBox.value.indexOf(strLastValue) != 0 ||
((arrOptions.length==0 || arrOptions.length==15 ) && !bNoResults) ||
(theTextBox.value.length <= strLastValue.length)){
objLastActive = theTextBox;
bMadeRequest = true
TypeAhead(theTextBox.value)
}
else if(!bMadeRequest){
BuildList(theTextBox.value);
}
strLastValue = theTextBox.value;
}
//request
function TypeAhead(xStrText){
var strParams = "q=" + xStrText +
"&where=" + theTextBox.obj.matchAnywhere;
var loader1 = new net.ContentLoader(theTextBox.obj.serverCode,
BuildChoices,null,"POST",strParams);
}
//switch show
function BuildChoices(){
var strText = this.req.responseText;
eval(strText);
BuildList(strLastValue);
bMadeRequest = false;
}
//show span
function BuildList(theText){
SetElementPosition(theTextBox);
var theMatches = MakeMatches(theText);
theMatches = theMatches.join().replace(/\,/gi,"");
if(theMatches.length > 0){
//这个地方是我今天刚修改的,项目组成员发现,如果在文本框下边有一个选择列表,就会出现遮挡效果。故添加一个iframe。
document.getElementById("spanOutput")
.innerHTML = "<IFRAME width=\"100%\" height=\"100%\" style=\"position:absolute; top:0px; z-index:-1; border-style:none;\"></IFRAME>"+theMatches;
document.getElementById(
"OptionsList_0").className=
"spanHighElement";
currentValueSelected = 0;
bNoResults = false;
}
else{
currentValueSelected = -1;
bNoResults = true;
if(theTextBox.obj.showNoMatchMessage)
document.getElementById(
"spanOutput").innerHTML =
"<span class='noMatchData'>" +
theTextBox.obj
.noMatchingDataMessage +
"</span>";
else HideTheBox();
}
}
function SetElementPosition(theTextBoxInt){
var selectedPosX = 0;
var selectedPosY = 0;
var theElement = theTextBoxInt;
if (!theElement) return;
var theElemHeight = theElement.offsetHeight;
var theElemWidth = theElement.offsetWidth;
while(theElement != null){
selectedPosX += theElement.offsetLeft;
selectedPosY += theElement.offsetTop;
theElement = theElement.offsetParent;
}
xPosElement = document.getElementById("spanOutput");
xPosElement.style.left = selectedPosX;
if(theTextBoxInt.obj.matchTextBoxWidth)
xPosElement.style.width = theElemWidth;
xPosElement.style.top = selectedPosY + theElemHeight
xPosElement.style.display = "block";
if(theTextBoxInt.obj.useTimeout){
xPosElement.onmouseout = StartTimeout;
xPosElement.onmouseover = EraseTimeout;
}
else{
xPosElement.onmouseout = null;
xPosElement.onmouseover = null;
}
}
var countForId = 0;
function MakeMatches(xCompareStr){
countForId = 0;
var matchArray = new Array();
var regExp = new RegExp(theTextBox.obj.regExAny +
xCompareStr,theTextBox.obj.regExFlags);
for(i=0;i<arrOptions.length;i++){
var theMatch = arrOptions[i][0].match(regExp);
if(theMatch){
matchArray[matchArray.length]=
CreateUnderline(arrOptions[i][0],
xCompareStr,i);
}
}
return matchArray;
}
var undeStart = "<span class='spanMatchText'>";
var undeEnd = "</span>";
var selectSpanStart = "<span style='width:100%;display:block;' class='spanNormalElement' onmouseover='SetHighColor(this)' ";
var selectSpanEnd ="</span>";
function CreateUnderline(xStr,xTextMatch,xVal){
selectSpanMid = "onclick='SetText(" + xVal + ")'" +
"id='OptionsList_" +
countForId + "' theArrayNumber='"+ xVal +"'>";
var regExp = new RegExp(theTextBox.obj.regExAny +
xTextMatch,theTextBox.obj.regExFlags);
var aStart = xStr.search(regExp);
var matchedText = xStr.substring(aStart,
aStart + xTextMatch.length);
countForId++;
return selectSpanStart + selectSpanMid +
xStr.replace(regExp,undeStart +
matchedText + undeEnd) + selectSpanEnd;
}
//Listing 10.17
function MoveHighlight(xDir){
if(currentValueSelected >= 0){
newValue = parseInt(currentValueSelected) + parseInt(xDir);
if(newValue > -1 && newValue < countForId){
currentValueSelected = newValue;
SetHighColor (null);
}
}
}
function SetHighColor(theTextBox){
if(theTextBox){
currentValueSelected =
theTextBox.id.slice(theTextBox.id.indexOf("_")+1,
theTextBox.id.length);
}
for(i = 0; i < countForId; i++){
document.getElementById('OptionsList_' + i).className =
'spanNormalElement';
}
document.getElementById('OptionsList_' +
currentValueSelected).className = 'spanHighElement';
}
//Listing 10.18
function SetText(xVal){
theTextBox.value = arrOptions[xVal][0]; //set text value
theTextBox.obj.hidden.value = arrOptions[xVal][1];
document.getElementById("spanOutput").style.display = "none";
currentValueSelected = -1; //remove the selected index
}
function GrabHighlighted(){
if(currentValueSelected >= 0){
xVal = document.getElementById("OptionsList_" +
currentValueSelected).getAttribute("theArrayNumber");
SetText(xVal);
HideTheBox();
}
}
function HideTheBox(){
document.getElementById("spanOutput").style.display = "none";
currentValueSelected = -1;
EraseTimeout();
}
//Listing 10.19
function EraseTimeout(){
clearTimeout(isTiming);
isTiming = false;
}
function StartTimeout(){
isTiming = setTimeout("HideTheBox()",
theTextBox.obj.theVisibleTime);
}
Step four:
/*
url-loading object and a request queue built on top of it
*/
/* namespacing object */ //some javacoder think is package object
var net=new Object();
net.READY_STATE_UNINITIALIZED=0;
net.READY_STATE_LOADING=1;
net.READY_STATE_LOADED=2;
net.READY_STATE_INTERACTIVE=3;
net.READY_STATE_COMPLETE=4;
/*--- content loader object for cross-browser requests ---*/
net.ContentLoader=function(url,onload,onerror,method,params,contentType){
this.req=null;
net.currentLoader=this;
this.onload=onload;
this.onerror=(onerror) ? onerror : this.defaultError;
this.loadXMLDoc(url,method,params,contentType);
}
net.ContentLoader.prototype.loadXMLDoc=function(url,method,params,contentType){
if (!method){
method="GET";
}
if (!contentType && method=="POST"){
contentType='application/x-www-form-urlencoded';