软讯网络 > 编程语言 > Java > Javascript噩梦-Ajax实现输入提示的调整与配置
【标 题】:Javascript噩梦-Ajax实现输入提示的调整与配置
【关键字】:
Javascript,Ajax
【来 源】:http://www.blogjava.net/richardeee/archive/2007/02/01/97380.html
Javascript噩梦-Ajax实现输入提示的调整与配置

经过一个星期的煎熬,终于把基于Ajax的输入提示功能实现了。太痛苦了,写Javascript的感觉就跟用NotePad来写代码一样,没有智能提示、弱类型、难调试……总之是太折磨人了。
本来自己写了一个比较简单的,但是由于我的页面上需要多个输入框,还要可以动态增加输入框,要把传回来的结果set入多个输入框,由于是使用的Struts标签库,<html:text>还没有id属性,让这个问题复杂了不少。
需求是这样的:
有一个页面,需要录入货品信息,货品有id,编号,名称,单位,单价,规格等属性,每个货品信息在表格中有一行,一行中有多个输入框,用于输入货品信息。在输入货品编号的时候,应该访问后台的商品信息库,寻找以前是否有输入过该编号的货品,如果有,把编号返回。支持用鼠标点击,键盘回车等方法选择货品,选择后应该把货品信息显示到各个输入框中供用户修改。如果该货品在商品信息库中标记为敏感商品,要作出提示。一个编号可以有多个货品。
改了3天代码,终于决定破釜沉舟,删掉重做。修改了《Ajax in Action》中的代码,Ajax in Action中的代码有些地方有错误,不仔细检查一遍还真不太容易发现。书中后台使用C#,前台是使用Rico来向某个url传参数的形式进行Ajax通信。返回的response类似:
<ajax-response>
??<response?type='object'?id='field1_updater'>
????<matches>
??????<text>XXX</text>
??????<value>XXX</value>
????</matches>
??</response>
</ajax-response>不过我不想写JSP或者Servlet,所以用了DWR,直接用spring中的BO把结果传回来:

cargobaseService.getByNumberAndCompany(this.lastRequestString,this.company,function(ajaxResponse)
{
//
});cargobaseService是使用DWR创建的Javascript对象:
dwr.xml:
<dwr>
??<allow>
????<create?creator="spring"?javascript?=?"cargobaseService">
????????<param?name="beanName"?value="cargobaseService"/>
????</create>
????<convert?match="com.gdnfha.atcs.cargobase.model.*"?converter="bean"></convert>
??</allow>
</dwr>

返回为下面对象的数组

var?cargoModel?=?
{
??cargoCompany:?XXX,
??cargoCurrency:?XXX,
??cargoDestination:?XXX,
??cargoId:?XXX,
??cargoImpose:?XXX,
??cargoName:?XXX,
??cargoNumber:?XXX,
??cargoSize:?XXX,
??cargoUnit:?XXX,
??cargoUnitPrice:?XXX,
??sensitive:?true|false
}?Javascript代码如下:
TextSuggest?=?Class.create();


TextSuggest.prototype?=?
{
????//构造函数

???initialize:?function(anId,company,?url,?options)?
{
??????this.id??????????=?anId;
??????this.company?=?company;
??????var?browser?=?navigator.userAgent.toLowerCase();
??????this.isIE????????=?browser.indexOf("msie")?!=?-1;
??????this.isOpera?????=?browser.indexOf("opera")!=?-1;
??????this.textInput???=?$(this.id);
??????this.suggestions?=?new?Array();
??????this.setOptions(options);
??????this.injectSuggestBehavior();
???},
????//设置参数

???setOptions:?function(options)?
{

??????this.options?=?
{
?????????suggestDivClassName:?'suggestDiv',
?????????suggestionClassName:?'suggestion',
?????????matchClassName?????:?'match',
?????????matchTextWidth?????:?true,
?????????selectionColor?????:?'#b1c09c',
?????????matchAnywhere??????:?false,
?????????ignoreCase?????????:?false,
?????????count??????????????:?10

??????}.extend(options?||?
{});
???},
????//注入输入提示行为

???injectSuggestBehavior:?function()?
{

??????if?(?this.isIE?)
?????????this.textInput.autocomplete?=?"off";
????//创建控制器
??????var?keyEventHandler?=?new?TextSuggestKeyHandler(this);
??????//主要是为了避免在按回车的时候把表单提交
??????new?Insertion.After(?this.textInput,
???????????????????????????'<input?type="text"?id="'+this.id+'_preventtsubmit'+'"?style="display:none"/>'?);
??????new?Insertion.After(?this.textInput,
???????????????????????????'<input?type="hidden"?name="'+this.id+'_hidden'+'"?id="'+this.id+'_hidden'+'"/>'?);
????//创建div层
??????this.createSuggestionsDiv();
???},
????//处理输入信息

???handleTextInput:?function()?
{
?????var?previousRequest????=?this.lastRequestString;
?????this.lastRequestString?=?this.textInput.value;
?????if?(?this.lastRequestString?==?""?)
????????this.hideSuggestions();

?????else?if?(?this.lastRequestString?!=?previousRequest?)?
{
?????????//访问数据源
????????this.sendRequestForSuggestions();
?????}
???},
????//选择框上移

???moveSelectionUp:?function()?
{

??????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)?
{
??????var?span?=?$(?this.id?+?"_"?+?this.selectedIndex?);

??????if?(?span?)
{
??????????//消除以前的样式
?????????span.style.backgroundColor?=?"";
??????}
??????this.selectedIndex?=?n;
??????var?span?=?$(?this.id?+?"_"?+?this.selectedIndex?);

??????if?(?span?)
{
??????????//更新新样式
?????????span.style.backgroundColor?=?this.options.selectionColor;
??????}
???},
????//发送请求

???sendRequestForSuggestions:?function()?
{

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

?????this.handlingRequest?=?true;
?????this.callDWRAjaxEngine();
???},

????//使用DWR访问后台

???callDWRAjaxEngine:?function()?
{
???????????//保存当前对象指针
???????????var?tempThis?=?this;

???????????cargobaseService.getByNumberAndCompany(this.lastRequestString,this.company,function(ajaxResponse)
{
????????????tempThis.suggestions?=?ajaxResponse;

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

??????????????}else?
{
?????????????????tempThis.updateSuggestionsDiv();
?????????????????tempThis.showSuggestions();
?????????????????tempThis.updateSelection(0);
??????????????}
??????????????tempThis.handlingRequest?=?false;

????????????if?(?tempThis.pendingRequest?)?
{
????????????????tempThis.pendingRequest????=?false;
?????????????????tempThis.lastRequestString?=?this.textInput.value;
?????????????????tempThis.sendRequestForSuggestions();
??????????????}
???????????});
???},
???//显示信息

???setInputFromSelection:?function()?
{
???????var?index?=?this.id.split("_");
???????var?trId?=?"cargoTr_"?+?index[1];
???????var?trElement?=?$(trId);
???????var?cellNodes?=?trElement.childNodes;
?????var?suggestion??=?this.suggestions[?this.selectedIndex?];

????for(var?i?=?0;?i?<?cellNodes.length;?i++)
{
????????var?cargo?=?cellNodes[i].firstChild;

????????if(cargo.name?==?"cargoName")
{
????????????cargo.value?=?suggestion.cargoName;
????????}

????????if(cargo.name?==?"cargoSize")
{
????????????cargo.value?=?suggestion.cargoSize;
????????}

????????if(cargo.name?==?"cargoUnit")
{
????????????cargo.value?==?suggestion.cargoUnit;
????????}

????????if(cargo.name?==?"cargoDestination")
{
????????????cargo.value?=?suggestion.cargoDestination;
????????}

????????if(cargo.name?==?"cargoUnitPrice")
{
????????????cargo.value?=?suggestion.cargoUnitPrice;
????????}
????}
?????this.textInput.value?=?suggestion.cargoNumber;
?????//敏感提示

?????if(suggestion.sensitive)
{
?????????var?warnStr?=?"注意!\n编号:"+suggestion.cargoNumber
?????????????????????????????????+"\n名称:"?+?suggestion.cargoName
?????????????????????????????????+"\n为敏感商品!";
?????????alert(warnStr);?
?????}
?????this.hideSuggestions();
???},
????//显示层

???showSuggestions:?function()?
{
??????var?divStyle?=?this.suggestionsDiv.style;
??????if?(?divStyle.display?==?''?)
?????????return;
??????this.positionSuggestionsDiv();
??????divStyle.display?=?'';
???},
????//定位层

???positionSuggestionsDiv:?function()?
{
??????var?textPos?=?RicoUtil.toDocumentPosition(this.textInput);
??????var?divStyle?=?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
{
??????var?styleFunc?=?RicoUtil.getElementsComputedStyle;
??????var?lPad????=?styleFunc(?this.suggestionsDiv,?"paddingLeft",??????"padding-left"?);
??????var?rPad????=?styleFunc(?this.suggestionsDiv,?"paddingRight",?????"padding-right"?);
??????var?lBorder?=?styleFunc(?this.suggestionsDiv,?"borderLeftWidth",??"border-left-width"?);
??????var?rBorder?=?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;

??????return?parseInt(lPad)?+?parseInt(rPad)?+?parseInt(lBorder)?+?parseInt(rBorder);

?????}catch?(e)
{
??????return?0;
?????}
???},
????//隐藏层

???hideSuggestions:?function()?
{
??????this.suggestionsDiv.style.display?=?'none';
???},
????//创建层

???createSuggestionsDiv:?function()?
{
??????this.suggestionsDiv?=?document.createElement("div");
??????this.suggestionsDiv.className?=?this.options.suggestDivClassName;

??????var?divStyle?=?this.suggestionsDiv.style;
??????divStyle.position?=?'absolute';
??????divStyle.zIndex???=?101;
??????divStyle.display??=?"none";

??????this.textInput.parentNode.appendChild(this.suggestionsDiv);
???},
????//更新层

???updateSuggestionsDiv:?function()?
{
??????this.suggestionsDiv.innerHTML?=?"";
??????var?suggestLines?=?this.createSuggestionSpans();
??????for?(?var?i?=?0?;?i?<?suggestLines.length?;?i++?)
?????????this.suggestionsDiv.appendChild(suggestLines[i]);
???},
????//创建层中的选项span

???createSuggestionSpans:?function()?
{
??????var?regExpFlags?=?"";
??????if?(?this.options.ignoreCase?)
?????????regExpFlags?=?'i';
??????var?startRegExp?=?"^";
??????if?(?this.options.matchAnywhere?)
?????????startRegExp?=?'';
?????????//正则表达式匹配
??????var?regExp??=?new?RegExp(?startRegExp?+?this.lastRequestString,?regExpFlags?);
??????var?suggestionSpans?=?new?Array();
??????for?(?var?i?=?0?;?i?<?this.suggestions.length?;?i++?)
?????????suggestionSpans.push(?this.createSuggestionSpan(?i,?regExp?)?)

??????return?suggestionSpans;
???},
????//创建单个选项span

???createSuggestionSpan:?function(?n,?regExp?)?
{
??????var?suggestion?=?this.suggestions[n];

??????var?suggestionSpan?=?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);
??????var?textValues?=?this.splitTextValues(?suggestion.cargoNumber+"",
?????????????????????????????????????????????this.lastRequestString.length,
?????????????????????????????????????????????regExp?);
??????var?textMatchSpan?=?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?)?);

??????return?suggestionSpan;
???},
????//鼠标经过处理

![]()