Ajax学习--输入前提示

本文介绍了一个基于Ajax的文本提示组件的实现方法,包括如何使用Ajax进行数据加载及响应处理,以及如何创建一个可复用的文本输入建议组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



//--------------------mContentLoader.js
/**//*
*Ajax的辅助对象,执行所有与Ajax处理相关的工作
*
*/

varnet=newObject();

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;

/**//*
*构造函数
*component指定这个辅助所提供的对象,并假定component有一个ajaxUpdate()方法处理响应,一个handleError()方法处理错误
*url指定这个辅助从服务器端获取数据时调用的url
*mothd指定HTTP请求方法,有效值有GET和POST
*requestParams以key=value格式的字符串组形势指定一组传递给请求的请求参数
*/

net.ContentLoader
=function(component,url,method,requestParams){
this.component=component;
this.url=url;
this.requestParams=requestParams;
this.method=method;
}


net.ContentLoader.prototype
={

getTransport:
function(){
vartransport;
if(window.XMLHttpRequest)
transport
=newXMLHttpRequest();
elseif(window.ActiveXObject){
try{
transport
=newActiveXObject('Msxml2.XMLHTTP');
}

catch(err){
transport
=newActiveXObject('Microsoft.XMLHTTP');
}

}

returntransport;
}
,

sendRequest:
function(){

//if(window.netscape&&window.netscape.security.PrivilegeManager.enablePrivilege)
//netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');

varrequestParams=[]
for(vari=0;i<arguments.length;i++)
requestParams.push(arguments[i]);

varoThis=this;
varrequest=this.getTransport();
request.open(
this.method,this.url,true);
request.setRequestHeader('Content
-Type','application/x-www-form-urlencoded');
request.onreadystatechange
=function(){oThis.handleAjaxResponse(request)};
request.send(
this.queryString(requestParams));
}
,

queryString:
function(args){

varrequestParams=[];
for(vari=0;i<this.requestParams.length;i++)
requestParams.push(
this.requestParams[i]);
for(varj=0;j<args.length;j++)
requestParams.push(args[j]);

varqueryString="";
if(requestParams&&requestParams.length>0){
for(vari=0;i<requestParams.length;i++)
queryString
+=requestParams[i]+'&';
queryString
=queryString.substring(0,queryString.length-1);
}

returnqueryString;
}
,

handleAjaxResponse:
function(request){
if(request.readyState==net.READY_STATE_COMPLETE){
if(this.isSuccess(request))
this.component.ajaxUpdate(request);
else
this.component.handleError(request);
}

}
,

isSuccess:
function(request){
returnrequest.status==0
||(request.status>=200&&request.status<300);
}


}
;


//--------------------mTextSuggest.js
/**//*
*输入前提示组件,可重用在大部分需要这些功能的应用中,为此考虑一下特征
*1.不修改HTML标记,只简单修改head部分来注入组件行为
*2.组件能够使用不同的URL,并为所有配置选项提供合理的默认值
*3.组件不引入任何全局变量,防止全局变量混乱
*4.组件使用开源框架,以减少编码工作量,并提高方案的质量和健壮性
*/



/**//*
************************************创建TextSuggest***********************************************
*/

TextSuggest
=Class.create();

TextSuggest.prototype
={

/**//*
*构造函数
*andId:要附加提示行为的文本字段的ID
*url:处理请求的服务器URL
*options:options对象为组件的每一个配置参数提供一个属性
*/

initialize:
function(anId,url,options){
this.id=anId;
this.textInput=$(this.id);

//检测浏览器类型
varbrowser=navigator.userAgent.toLowerCase();
this.isIE=browser.indexOf("msie")!=-1;
this.isOpera=browser.indexOf("opera")!=-1;

this.suggestions=[];
this.setOptions(options);
this.initAjax(url);

this.injectSuggestBehavior();
}
,


/**//*
*为options每个属性都指定一个默认值
*然后,使用在构造时传入的options对象调用Prototype库的extend()方法,来覆盖默认值
*最后结果是一个合并的options对象,包含默认值和指定的覆盖值
*/

setOptions:
function(options){
this.options={
suggestDivClassName:'suggestDiv',
//指定用来保存提示的生成div元素的css类名
suggestionClassName:'suggestion',//指定用来保存每一条提示的生成span元素的css类名
matchClassName:'match',//指定用来保存匹配用户输入内容的提示部分的span元素的css类名
matchTextWidth:true,//用来指示为提示生成的div是否需要将自身大小设置为与它附加到的文本字段的宽度匹配
selectionColor:'#b1c09c',//为选中的提示的背景颜色指定一个十六进制值
matchAnywhere:false,//指定匹配是只查找字符串的开始位置,还是查找任意位置
ignoreCase:false,//指定匹配是否是区别大小写的
count:10//显示最大提示数量
}
.extend(options||{});
}
,


/**//*
************************************支持Ajax***********************************************
*/


//-----------------------文本提示--发送Ajax请求
/**//*
*发送请求限制
*如果没有正在处理的请求,就调用callRicoAjaxEngine()来发送请求,反之不发送
*通过设置一个内部布尔属性this.pendingRequest实现,当Ajax请求发送时值为true,当返回的请求被处理后值为false
*用来基于服务器的处理速度限制事件的发送速度
*/

sendRequestForSuggestions:
function(){

if(this.handlingRequest){
this.pendingRequest=true;
return;
}


this.handlingRequest=true;
this.callRicoAjaxEngine();
}
,

/**//*
*使用Rico提供的一个出色的Ajax处理函数
*ajaxEngine这个API支持为请求注册逻辑名,和注册知道如何处理Ajax响应的对象
*ajaxEngine.registerRequest()为一个(可能很长或很怪的)URL注册逻辑名,在发送请求时可以使用这个逻辑名
*ajaxEngine.registerAjaxObject()用来注册一个Ajax处理对象
*/

initAjax:
function(url){
ajaxEngine.registerRequest(
this.id+'_request',url);
ajaxEngine.registerAjaxObject(
this.id+'_updater',this);
}
,

/**//*
*发送请求
*先将对象的内部状态和options对象的特定属性存入数组callParms
*再将外部请求参数存入数组callParms
*通过ajaxEngine.sendRequest.apply(ajaxEngine,callParms)发送
*apply()方法见最后注释
*/

callRicoAjaxEngine:
function(){
varcallParms=[];
callParms.push(
this.id+'_request');
callParms.push('id
='+this.id);
callParms.push('count
='+this.options.count);
callParms.push('query
='+this.lastRequestString);
callParms.push('match_anywhere
='+this.options.matchAnywhere);
callParms.push('ignore_case
='+this.options.ignoreCase);

varadditionalParms=this.options.requestParameters||[];
for(vari=0;i<additionalParms.length;i++)
callParms.push(additionalParms[i]);

ajaxEngine.sendRequest.apply(ajaxEngine,callParms);
}
,

//-----------------------文本提示--处理Ajax请求

/**//*
*处理请求
*224先通过createSuggestions()方法将响应解析成提示在内存中的表现形式,保存在suggestions属性中
*226如果没找到提示,将探出框隐藏,并清空隐藏字段中的内部值
*230如果找到提示,创建下拉框的UI元素,使用提示组装,并显示给用户
*236最后将this.handlingRequest重新设置为false,表示响应处理完成
*/

ajaxUpdate:
function(ajaxResponse){

this.createSuggestions(ajaxResponse);

if(this.suggestions.length==0){
this.hideSuggestions();
$(
this.id+"_hidden").value="";
}

else{
this.updateSuggestionsDiv();
this.showSuggestions();
this.updateSelection(0);
}


this.handlingRequest=false;

if(this.pendingRequest){
this.pendingRequest=false;
this.lastRequestString=this.textInput.value;
this.sendRequestForSuggestions();
}

}
,

createSuggestions:
function(ajaxResponse){
this.suggestions=[];
varentries=ajaxResponse.getElementsByTagName('entry');
for(vari=0;i<entries.length;i++){
varstrText=this.getElementContent(entries[i].getElementsByTagName('text')[0]);
varstrValue=this.getElementContent(entries[i].getElementsByTagName('value')[0]);
this.suggestions.push({text:strText,value:strValue});
}

}
,

/**//*
************************************事件处理***********************************************
*/


//行为注入
injectSuggestBehavior:function(){

if(this.isIE)
this.textInput.autocomplete="off";//关闭IE自动完成

varkeyEventHandler=newTextSuggestKeyHandler(this);//创建控制器

//Insertion.After由Prototype库提供,添加一个不可见文本字段来防止回车键提交表单
newInsertion.After(this.textInput,
'
<inputtype="text"id="'+this.id+'_preventtsubmit'+'"style="display:none"/>');
newInsertion.After(this.textInput,
'
<inputtype="hidden"name="'+this.id+'_hidden'+'"id="'+this.id+'_hidden'+'"/>');

this.createSuggestionsDiv();//创建UI
}
,

//TextSuggest的选择处理方法
moveSelectionUp:function(){
//selectedIndex:select对象中当前被选option的下标
if(this.selectedIndex>0){
this.updateSelection(this.selectedIndex-1);
}

}
,

moveSelectionDown:
function(){
if(this.selectedIndex<(this.suggestions.length-1)){
this.updateSelection(this.selectedIndex+1);
}

}
,

updateSelection:
function(n){
varspan=$(this.id+"_"+this.selectedIndex);
if(span){
span.style.backgroundColor
="";//清除之前的选择
}

this.selectedIndex=n;
varspan=$(this.id+"_"+this.selectedIndex);
if(span){
span.style.backgroundColor
=this.options.selectionColor;
}

}
,

//文本输入处理函数
handleTextInput:function(){
varpreviousRequest=this.lastRequestString;//上次请求的值
this.lastRequestString=this.textInput.value;//现在请求的值
if(this.lastRequestString=="")
this.hideSuggestions();
elseif(this.lastRequestString!=previousRequest){
this.sendRequestForSuggestions();//数据的Ajax请求
}

}
,

setInputFromSelection:
function(){
varhiddenInput=$(this.id+"_hidden");
varsuggestion=this.suggestions[this.selectedIndex];

this.textInput.value=suggestion.text;//更新可见的值
hiddenInput.value=suggestion.value;//更新隐藏的值
this.hideSuggestions();
}
,



/**//*
************************************提示的弹出框界面***********************************************
*/


//创建DIV
createSuggestionsDiv:function(){
this.suggestionsDiv=document.createElement("div");//创建DIV
this.suggestionsDiv.className=this.options.suggestDivClassName;//设置样式

vardivStyle=this.suggestionsDiv.style;//添加行为样式
divStyle.position='absolute';
divStyle.zIndex
=101;
divStyle.display
="none";

this.textInput.parentNode.appendChild(this.suggestionsDiv);//插入到文档中
}
,

//定位弹出框
positionSuggestionsDiv:function(){
//通过Rico提供的toDocumentPosition()方法来计算文本字段的绝对位置
vartextPos=RicoUtil.toDocumentPosition(this.textInput);
vardivStyle=this.suggestionsDiv.style;
divStyle.top
=(textPos.y+this.textInput.offsetHeight)+"px";
divStyle.left
=textPos.x+"px";

if(this.options.matchTextWidth)
divStyle.width
=(this.textInput.offsetWidth-this.padding())+"px";
}
,

//计算左边和右边的填充值
padding:function(){
try{
varstyleFunc=RicoUtil.getElementsComputedStyle;
varlPad=styleFunc(this.suggestionsDiv,"paddingLeft","padding-left");
varrPad=styleFunc(this.suggestionsDiv,"paddingRight","padding-right");
varlBorder=styleFunc(this.suggestionsDiv,"borderLeftWidth","border-left-width");
varrBorder=styleFunc(this.suggestionsDiv,"borderRightWidth","border-right-width");

lPad
=isNaN(lPad)?0:lPad;
rPad
=isNaN(rPad)?0:rPad;
lBorder
=isNaN(lBorder)?0:lBorder;
rBorder
=isNaN(rBorder)?0:rBorder;

returnparseInt(lPad)+parseInt(rPad)+parseInt(lBorder)+parseInt(rBorder);
}
catch(e){
return0;
}

}
,

//创建弹出框的内容
updateSuggestionsDiv:function(){
this.suggestionsDiv.innerHTML="";//除去以前的内容
varsuggestLines=this.createSuggestionSpans();//创建新内容
for(vari=0;i<suggestLines.length;i++)
this.suggestionsDiv.appendChild(suggestLines[i]);
}
,

//创建提示列表的条目
createSuggestionSpans:function(){
varregExpFlags="";
if(this.options.ignoreCase)
regExpFlags
='i';
varstartRegExp="^";
if(this.options.matchAnywhere)
startRegExp
='';

varregExp=newRegExp(startRegExp+this.lastRequestString,regExpFlags);

varsuggestionSpans=[];
for(vari=0;i<this.suggestions.length;i++)
suggestionSpans.push(
this.createSuggestionSpan(i,regExp))

returnsuggestionSpans;
}
,

//创建列表的条目span
createSuggestionSpan:function(n,regExp){
varsuggestion=this.suggestions[n];

varsuggestionSpan=document.createElement("span");
suggestionSpan.className
=this.options.suggestionClassName;
suggestionSpan.style.width
='100%';
suggestionSpan.style.display
='block';
suggestionSpan.id
=this.id+"_"+n;
suggestionSpan.onmouseover
=this.mouseoverHandler.bindAsEventListener(this);
suggestionSpan.onclick
=this.itemClickHandler.bindAsEventListener(this);

vartextValues=this.splitTextValues(suggestion.text,
this.lastRequestString.length,
regExp);

vartextMatchSpan=document.createElement("span");
textMatchSpan.id
=this.id+"_match_"+n;
textMatchSpan.className
=this.options.matchClassName;
textMatchSpan.onmouseover
=this.mouseoverHandler.bindAsEventListener(this);
textMatchSpan.onclick
=this.itemClickHandler.bindAsEventListener(this);

textMatchSpan.appendChild(document.createTextNode(textValues.mid));

suggestionSpan.appendChild(document.createTextNode(textValues.start));
suggestionSpan.appendChild(textMatchSpan);
suggestionSpan.appendChild(document.createTextNode(textValues.end));

returnsuggestionSpan;
}
,

splitTextValues:
function(text,len,regExp){
varstartPos=text.search(regExp);
varmatchText=text.substring(startPos,startPos+len);
varstartText=startPos==0?"":text.substring(0,startPos);
varendText=text.substring(startPos+len);
return{start:startText,mid:matchText,end:endText};
}
,

//列表条目的鼠标事件处理函数
mouseoverHandler:function(e){
varsrc=e.srcElement?e.srcElement:e.target;
varindex=parseInt(src.id.substring(src.id.lastIndexOf('_')+1));
this.updateSelection(index);
}
,

itemClickHandler:
function(e){
this.mouseoverHandler(e);
this.hideSuggestions();
this.textInput.focus();
}
,

//显示和隐藏弹出框
showSuggestions:function(){
vardivStyle=this.suggestionsDiv.style;
if(divStyle.display=='')
return;
this.positionSuggestionsDiv();
divStyle.display
='';
}
,

hideSuggestions:
function(){
this.suggestionsDiv.style.display='none';
}
,

getElementContent:
function(element){
returnelement.firstChild.data;
}

}



//---------------控制器对象,用来担任事件的代理


TextSuggestKeyHandler
=Class.create();

TextSuggestKeyHandler.prototype
={

/**//*
*构造方法
*控制器保存提示组件的引用和HTML标单的输入字段,通过this.addKeyHandling()为输入字段添加处理函数
*/

initialize:
function(textSuggest){
this.textSuggest=textSuggest;
this.input=this.textSuggest.textInput;
this.addKeyHandling();
}
,

//bindAsEventListener()是prototype库提供的一个闭包机制,该机制允许处理函数调用控制器的方法
addKeyHandling:function(){
this.input.onkeyup=this.keyupHandler.bindAsEventListener(this);
this.input.onkeydown=this.keydownHandler.bindAsEventListener(this);
this.input.onblur=this.onblurHandler.bindAsEventListener(this);
if(this.isOpera)
this.input.onkeypress=this.keyupHandler.bindAsEventListener(this);
}
,

//处理按下按键
keydownHandler:function(e){
varupArrow=38;//上箭头
vardownArrow=40;//下箭头

if(e.keyCode==upArrow){
this.textSuggest.moveSelectionUp();
setTimeout(
this.moveCaretToEnd.bind(this),1);
}

elseif(e.keyCode==downArrow){
this.textSuggest.moveSelectionDown();
}

}
,

//处理放开按键
keyupHandler:function(e){
if(this.input.length==0&&!this.isOpera)
this.textSuggest.hideSuggestions();

if(!this.handledSpecialKeys(e))
this.textSuggest.handleTextInput();
}
,

//几个特殊按键
handledSpecialKeys:function(e){
varenterKey=13;//上箭头
varupArrow=38;//下箭头
vardownArrow=40;//回车键

if(e.keyCode==upArrow||e.keyCode==downArrow){
returntrue;
}

elseif(e.keyCode==enterKey){
this.textSuggest.setInputFromSelection();
returntrue;
}


returnfalse;
}
,

//修改上箭头在文本字段中使光标后退的默认行为
moveCaretToEnd:function(){
varpos=this.input.value.length;
if(this.input.setSelectionRange){
this.input.setSelectionRange(pos,pos);
}

elseif(this.input.createTextRange){
varm=this.input.createTextRange();
m.moveStart('character',pos);
m.collapse();
m.select();
}

}
,

onblurHandler:
function(e){
if(this.textSuggest.suggestionsDiv.style.display=='')
this.textSuggest.setInputFromSelection();
this.textSuggest.hideSuggestions();
}


}
;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值