基于AJAX的自动完成
我想大家在访问某些网站的时候都曾见到过基于Ajax的自动完成功能,比如
一、引出Ajax的自动完成
现在要实现一个员工信息查询的功能,即根据输入的名字检索员工的详细信息。这是一个简单的数据表查询,在ASP.NET中实现这样的功能是比较简单的.
从上面可以看出,这种员工信息查询功能还存在一些不足,比如用户可能记不全员工的名字,只记得前面几个字母是什么,这样用户只能根据记忆猜测,一遍遍地尝试。如果在用户输入的同时,输入框下方可以给出相应的提示,辅助用户输入,那么用户进行检索的速度和成功率就会大大提高.这就是基于Ajax的自动完成功能.
二、自动完成功能的实现
实现这样的功能需要按以下的步骤进行。
· 服务器端提供GetSearchItems方法给客户端,用来返回满足条件的员工列表。
· 客户端的输入框需要增加onkeydown响应函数,以便即时获取满足条件的员工列表。
· 通过客户端的JavaScript动态列出待选结果的列表,同时还要提供键盘和鼠标的响应。
三、服务器端实现
本文采用AjaxPro.NET作为Ajax开发框架,首先为使用AjaxPro.NET做一些准备工作。 添加对AjaxPro.dll的引用,修改Web.config配置文件,在system.web节点下加入如下配置:
1
<
httpHandlers
>
2 <!-- Register the ajax handler -->
3 < add verb ="POST,GET" path ="ajaxpro/*.ashx" type ="AjaxPro.AjaxHandlerFactory, AjaxPro" />
4 </ httpHandlers >
2 <!-- Register the ajax handler -->
3 < add verb ="POST,GET" path ="ajaxpro/*.ashx" type ="AjaxPro.AjaxHandlerFactory, AjaxPro" />
4 </ httpHandlers >
在页面后台代码( Default.aspx.cs )的 Page_Load 方法中增加下面的代码:
1
protected
void
Page_Load(
object
sender, EventArgs e)
2 {
3 AjaxPro.Utility.RegisterTypeForAjax(typeof(_Default));
4}
2 {
3 AjaxPro.Utility.RegisterTypeForAjax(typeof(_Default));
4}
下面定义提供给客户端调用的方法GetSearchItems(),参数query为模糊查询的关键字值:
1
[AjaxPro.AjaxMethod()]
2 public ArrayList GetSearchItems( string query)
3 {
4 ArrayList items = new ArrayList();
5 StringBuilder queryString = new StringBuilder();
6 queryString.Append("select employeeid,lastname,firstname,title,titleofcourtesy from dbo.Employees");
7 queryString.Append(" where firstname like '%" + query + "%'");
8
9 DataSet ds = DataBase.Instance.ReturnDataSet(queryString.ToString());
10 for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
11 {
12 items.Add(ds.Tables[0].Rows[i][2].ToString());
13 }
14 return items;
15}
GetSearchItems
方法返回一个
ArrayList
对象,它将包含所有以用户输入字符串的员工名字。2 public ArrayList GetSearchItems( string query)
3 {
4 ArrayList items = new ArrayList();
5 StringBuilder queryString = new StringBuilder();
6 queryString.Append("select employeeid,lastname,firstname,title,titleofcourtesy from dbo.Employees");
7 queryString.Append(" where firstname like '%" + query + "%'");
8
9 DataSet ds = DataBase.Instance.ReturnDataSet(queryString.ToString());
10 for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
11 {
12 items.Add(ds.Tables[0].Rows[i][2].ToString());
13 }
14 return items;
15}
四、客户端实现
相对于服务器端的方法而言,客户端的处理要复杂得多。首先来分析如何根据服务器端返回的 ArrayList 对象展示结果。 这里用到了 Web 编程中“层”( div )的概念,通过 JavaScript 和 DOM 创建一个新的层 div ,将 ArrayList 中的每一个条目都作为其子节点加入到 div 中,而每一个条目也被看作是一个 div ,其中具体的文本内容则是一个 span 对象。
除了显示待选的结果之外,下拉区域还要对键盘、鼠标事件做出响应;为了实时地显示待选结果,还需要定时更新待选结果的列表。这些功能都封装在 lookup.js中。下面是lookeu.js的定义:
1
//
下拉区背景色
2 var DIV_BG_COLOR = " #EEE " ;
3 // 高亮显示条目颜色
4 var DIV_HIGHLIGHT_COLOR = " #C30 " ;
5 // 字体
6 var DIV_FONT = " Arial " ;
7 // 下拉区内补丁大小
8 var DIV_PADDING = " 2px " ;
9 // 下拉区边框样式
10 var DIV_BORDER = " 1px solid #CCC " ;
11
12
13 // 文本输入框
14 var queryField;
15 // 下拉区id
16 var divName;
17 // IFrame名称
18 var ifName;
19 // 记录上次选择的值
20 var lastVal = "" ;
21 // 当前选择的值
22 var val = "" ;
23 // 显示结果的下拉区
24 var globalDiv;
25 // 下拉区是否设置格式的标记
26 var divFormatted = false ;
27
28 /**
29InitQueryCode函数必须在<body onload>事件的响应函数中调用,其中:
30queryFieldName为文本框控件的id,
31hiddenDivName为显示下拉区div的id
32*/
33 function InitQueryCode (queryFieldName, hiddenDivName)
34 {
35 // 指定文本输入框的onblur和onkeydown响应函数
36 queryField = document.getElementById(queryFieldName);
37 queryField.onblur = hideDiv;
38 queryField.onkeydown = keypressHandler;
39
40 // 设置queryField的autocomplete属性为"off"
41 queryField.autocomplete = "off";
42
43 // 如果没有指定hiddenDivName,取默认值"querydiv"
44 if (hiddenDivName)
45 {
46 divName = hiddenDivName;
47 }
48 else
49 {
50 divName = "querydiv";
51 }
52
53 // IFrame的name
54 ifName = "queryiframe";
55
56 // 100ms后调用mainLoop函数
57 setTimeout("mainLoop()", 100);
58}
59
60 /**
61获取下拉区的div,如果没有则创建之
62*/
63 function getDiv (divID)
64 {
65 if (!globalDiv)
66 {
67 // 如果div在页面中不存在,创建一个新的div
68
69 if (!document.getElementById(divID))
70 {
71 var newNode = document.createElement("div");
72 newNode.setAttribute("id", divID);
73 document.body.appendChild(newNode);
74 }
75
76 // globalDiv设置为div的引用
77 globalDiv = document.getElementById(divID);
78
79 // 计算div左上角的位置
80 var x = queryField.offsetLeft;
81 var y = queryField.offsetTop + queryField.offsetHeight;
82 var parent = queryField;
83 while (parent.offsetParent)
84 {
85 parent = parent.offsetParent;
86 x += parent.offsetLeft;
87 y += parent.offsetTop;
88 }
89
90 // 如果没有对div设置格式,则为其设置相应的显示样式
91 if (!divFormatted)
92 {
93 globalDiv.style.backgroundColor = DIV_BG_COLOR;
94 globalDiv.style.fontFamily = DIV_FONT;
95 globalDiv.style.padding = DIV_PADDING;
96 globalDiv.style.border = DIV_BORDER;
97 globalDiv.style.width = "100px";
98 globalDiv.style.fontSize = "90%";
99
100 globalDiv.style.position = "absolute";
101 globalDiv.style.left = x + "px";
102 globalDiv.style.top = y + "px";
103 globalDiv.style.visibility = "hidden";
104 globalDiv.style.zIndex = 10000;
105
106 divFormatted = true;
107 }
108 }
109
110 return globalDiv;
111}
112
113 /**
114根据返回的结果集显示下拉区
115*/
116 function showQueryDiv(resultArray)
117 {
118 // 获取div的引用
119 var div = getDiv(divName);
120
121 // 如果div中有内容,则删除之
122 while (div.childNodes.length > 0)
123 div.removeChild(div.childNodes[0]);
124
125 // 依次添加结果
126 for (var i = 0; i < resultArray.length; i++)
127 {
128 // 每一个结果也是一个div
129 var result = document.createElement("div");
130 // 设置结果div的显示样式
131 result.style.cursor = "pointer";
132 result.style.padding = "2px 0px 2px 0px";
133 // 设置为未选中
134 _unhighlightResult(result);
135 // 设置鼠标移进、移出等事件响应函数
136 result.onmousedown = selectResult;
137 result.onmouseover = highlightResult;
138 result.onmouseout = unhighlightResult;
139
140 // 结果的文本是一个span
141 var result1 = document.createElement("span");
142 // 设置文本span的显示样式
143 result1.className = "result1";
144 result1.style.textAlign = "left";
145 result1.style.fontWeight = "bold";
146 result1.innerHTML = resultArray[i];
147
148 // 将span添加为结果div的子节点
149 result.appendChild(result1);
150
151 // 将结果div添加为下拉区的子节点
152 div.appendChild(result);
153 }
154
155 // 如果结果集不为空,则显示,否则不显示
156 showDiv(resultArray.length > 0);
157}
158
159 /**
160用户点击某个结果时,将文本框的内容替换为结果的文本,
161并隐藏下拉区
162*/
163 function selectResult()
164 {
165 _selectResult(this);
166}
167
168 // 选择一个条目
169 function _selectResult(item)
170 {
171 var spans = item.getElementsByTagName("span");
172 if (spans)
173 {
174 for (var i = 0; i < spans.length; i++)
175 {
176 if (spans[i].className == "result1")
177 {
178 queryField.value = spans[i].innerHTML;
179 lastVal = val = escape(queryField.value);
180 mainLoop();
181 queryField.focus();
182 showDiv(false);
183 return;
184 }
185 }
186 }
187}
188
189 /**
190当鼠标移到某个条目之上时,高亮显示该条目
191*/
192 function highlightResult()
193 {
194 _highlightResult(this);
195}
196
197 function _highlightResult(item)
198 {
199 item.style.backgroundColor = DIV_HIGHLIGHT_COLOR;
200}
201
202 /**
203当鼠标移出某个条目时,正常显示该条目
204*/
205 function unhighlightResult()
206 {
207 _unhighlightResult(this);
208}
209
210 function _unhighlightResult(item)
211 {
212 item.style.backgroundColor = DIV_BG_COLOR;
213}
214
215 /**
216显示/不显示下拉区
217*/
218 function showDiv (show)
219 {
220 var div = getDiv(divName);
221 if (show)
222 {
223 div.style.visibility = "visible";
224 }
225 else
226 {
227 div.style.visibility = "hidden";
228 }
229 //adjustiFrame();
230}
231
232 /**
233隐藏下拉区
234*/
235 function hideDiv ()
236 {
237 showDiv(false);
238}
239
240 /**
241调整IFrame的位置,这是为了解决div可能会显示在输入框后面的问题
242*/
243 function adjustiFrame()
244 {
245 // 如果没有IFrame,则创建之
246 if (!document.getElementById(ifName))
247 {
248 var newNode = document.createElement("iFrame");
249 newNode.setAttribute("id", ifName);
250 newNode.setAttribute("src", "javascript:false;");
251 newNode.setAttribute("scrolling", "no");
252 newNode.setAttribute("frameborder", "0");
253 document.body.appendChild(newNode);
254 }
255
256 iFrameDiv = document.getElementById(ifName);
257 var div = getDiv(divName);
258
259 // 调整IFrame的位置与div重合,并在div的下一层
260 try
261 {
262 iFrameDiv.style.position = "absolute";
263 iFrameDiv.style.width = div.offsetWidth;
264 iFrameDiv.style.height = div.offsetHeight;
265 iFrameDiv.style.top = div.style.top;
266 iFrameDiv.style.left = div.style.left;
267 iFrameDiv.style.zIndex = div.style.zIndex - 1;
268 iFrameDiv.style.visibility = div.style.visibility;
269 }
270 catch (e)
271 {
272 }
273}
274
275 /**
276文本输入框的onkeydown响应函数
277*/
278 function keypressHandler (evt)
279 {
280 // 获取对下拉区的引用
281 var div = getDiv(divName);
282
283 // 如果下拉区不显示,则什么也不做
284 if (div.style.visibility == "hidden")
285 {
286 return true;
287 }
288
289 // 确保evt是一个有效的事件
290 if (!evt && window.event)
291 {
292 evt = window.event;
293 }
294 var key = evt.keyCode;
295
296 var KEYUP = 38;
297 var KEYDOWN = 40;
298 var KEYENTER = 13;
299 var KEYTAB = 9;
300
301 // 只处理上下键、回车键和Tab键的响应
302 if ((key != KEYUP) && (key != KEYDOWN) && (key != KEYENTER) && (key != KEYTAB))
303 {
304 return true;
305 }
306
307 var selNum = getSelectedSpanNum(div);
308 var selSpan = setSelectedSpan(div, selNum);
309
310 // 如果键入回车和Tab,则选择当前选择条目
311 if ((key == KEYENTER) || (key == KEYTAB))
312 {
313 if (selSpan)
314 {
315 _selectResult(selSpan);
316 }
317 evt.cancelBubble = true;
318 return false;
319 }
320 else //如果键入上下键,则上下移动选中条目
321 {
322 if (key == KEYUP)
323 {
324 selSpan = setSelectedSpan(div, selNum - 1);
325 }
326 if (key == KEYDOWN)
327 {
328 selSpan = setSelectedSpan(div, selNum + 1);
329 }
330 if (selSpan)
331 {
332 _highlightResult(selSpan);
333 }
334 }
335
336 // 显示下拉区
337 showDiv(true);
338 return true;
339}
340
341 /**
342获取当前选中的条目的序号
343*/
344 function getSelectedSpanNum(div)
345 {
346 var count = -1;
347 var spans = div.getElementsByTagName("div");
348 if (spans)
349 {
350 for (var i = 0; i < spans.length; i++)
351 {
352 count++;
353 if (spans[i].style.backgroundColor != div.style.backgroundColor)
354 {
355 return count;
356 }
357 }
358 }
359
360 return -1;
361}
362
363 /**
364选择指定序号的结果条目
365*/
366 function setSelectedSpan(div, spanNum)
367 {
368 var count = -1;
369 var thisSpan;
370 var spans = div.getElementsByTagName("div");
371 if (spans)
372 {
373 for (var i = 0; i < spans.length; i++)
374 {
375 if (++count == spanNum)
376 {
377 _highlightResult(spans[i]);
378 thisSpan = spans[i];
379 }
380 else
381 {
382 _unhighlightResult(spans[i]);
383 }
384 }
385 }
386
387 return thisSpan;
388}
389
InitQueryCode
函数必须在页面的
onload
响应中执行,该函数最后调用
setTimeout
方法执行了
mainLoop
方法。注意,
mainLoop
方法并没有在
lookup.js
中定义,必须在包含
lookup.js
文件的页面文件中增加该函数的定义。于此,我们就需要在Default.aspx页面上加入如下定义:2 var DIV_BG_COLOR = " #EEE " ;
3 // 高亮显示条目颜色
4 var DIV_HIGHLIGHT_COLOR = " #C30 " ;
5 // 字体
6 var DIV_FONT = " Arial " ;
7 // 下拉区内补丁大小
8 var DIV_PADDING = " 2px " ;
9 // 下拉区边框样式
10 var DIV_BORDER = " 1px solid #CCC " ;
11
12
13 // 文本输入框
14 var queryField;
15 // 下拉区id
16 var divName;
17 // IFrame名称
18 var ifName;
19 // 记录上次选择的值
20 var lastVal = "" ;
21 // 当前选择的值
22 var val = "" ;
23 // 显示结果的下拉区
24 var globalDiv;
25 // 下拉区是否设置格式的标记
26 var divFormatted = false ;
27
28 /**
29InitQueryCode函数必须在<body onload>事件的响应函数中调用,其中:
30queryFieldName为文本框控件的id,
31hiddenDivName为显示下拉区div的id
32*/
33 function InitQueryCode (queryFieldName, hiddenDivName)
34 {
35 // 指定文本输入框的onblur和onkeydown响应函数
36 queryField = document.getElementById(queryFieldName);
37 queryField.onblur = hideDiv;
38 queryField.onkeydown = keypressHandler;
39
40 // 设置queryField的autocomplete属性为"off"
41 queryField.autocomplete = "off";
42
43 // 如果没有指定hiddenDivName,取默认值"querydiv"
44 if (hiddenDivName)
45 {
46 divName = hiddenDivName;
47 }
48 else
49 {
50 divName = "querydiv";
51 }
52
53 // IFrame的name
54 ifName = "queryiframe";
55
56 // 100ms后调用mainLoop函数
57 setTimeout("mainLoop()", 100);
58}
59
60 /**
61获取下拉区的div,如果没有则创建之
62*/
63 function getDiv (divID)
64 {
65 if (!globalDiv)
66 {
67 // 如果div在页面中不存在,创建一个新的div
68
69 if (!document.getElementById(divID))
70 {
71 var newNode = document.createElement("div");
72 newNode.setAttribute("id", divID);
73 document.body.appendChild(newNode);
74 }
75
76 // globalDiv设置为div的引用
77 globalDiv = document.getElementById(divID);
78
79 // 计算div左上角的位置
80 var x = queryField.offsetLeft;
81 var y = queryField.offsetTop + queryField.offsetHeight;
82 var parent = queryField;
83 while (parent.offsetParent)
84 {
85 parent = parent.offsetParent;
86 x += parent.offsetLeft;
87 y += parent.offsetTop;
88 }
89
90 // 如果没有对div设置格式,则为其设置相应的显示样式
91 if (!divFormatted)
92 {
93 globalDiv.style.backgroundColor = DIV_BG_COLOR;
94 globalDiv.style.fontFamily = DIV_FONT;
95 globalDiv.style.padding = DIV_PADDING;
96 globalDiv.style.border = DIV_BORDER;
97 globalDiv.style.width = "100px";
98 globalDiv.style.fontSize = "90%";
99
100 globalDiv.style.position = "absolute";
101 globalDiv.style.left = x + "px";
102 globalDiv.style.top = y + "px";
103 globalDiv.style.visibility = "hidden";
104 globalDiv.style.zIndex = 10000;
105
106 divFormatted = true;
107 }
108 }
109
110 return globalDiv;
111}
112
113 /**
114根据返回的结果集显示下拉区
115*/
116 function showQueryDiv(resultArray)
117 {
118 // 获取div的引用
119 var div = getDiv(divName);
120
121 // 如果div中有内容,则删除之
122 while (div.childNodes.length > 0)
123 div.removeChild(div.childNodes[0]);
124
125 // 依次添加结果
126 for (var i = 0; i < resultArray.length; i++)
127 {
128 // 每一个结果也是一个div
129 var result = document.createElement("div");
130 // 设置结果div的显示样式
131 result.style.cursor = "pointer";
132 result.style.padding = "2px 0px 2px 0px";
133 // 设置为未选中
134 _unhighlightResult(result);
135 // 设置鼠标移进、移出等事件响应函数
136 result.onmousedown = selectResult;
137 result.onmouseover = highlightResult;
138 result.onmouseout = unhighlightResult;
139
140 // 结果的文本是一个span
141 var result1 = document.createElement("span");
142 // 设置文本span的显示样式
143 result1.className = "result1";
144 result1.style.textAlign = "left";
145 result1.style.fontWeight = "bold";
146 result1.innerHTML = resultArray[i];
147
148 // 将span添加为结果div的子节点
149 result.appendChild(result1);
150
151 // 将结果div添加为下拉区的子节点
152 div.appendChild(result);
153 }
154
155 // 如果结果集不为空,则显示,否则不显示
156 showDiv(resultArray.length > 0);
157}
158
159 /**
160用户点击某个结果时,将文本框的内容替换为结果的文本,
161并隐藏下拉区
162*/
163 function selectResult()
164 {
165 _selectResult(this);
166}
167
168 // 选择一个条目
169 function _selectResult(item)
170 {
171 var spans = item.getElementsByTagName("span");
172 if (spans)
173 {
174 for (var i = 0; i < spans.length; i++)
175 {
176 if (spans[i].className == "result1")
177 {
178 queryField.value = spans[i].innerHTML;
179 lastVal = val = escape(queryField.value);
180 mainLoop();
181 queryField.focus();
182 showDiv(false);
183 return;
184 }
185 }
186 }
187}
188
189 /**
190当鼠标移到某个条目之上时,高亮显示该条目
191*/
192 function highlightResult()
193 {
194 _highlightResult(this);
195}
196
197 function _highlightResult(item)
198 {
199 item.style.backgroundColor = DIV_HIGHLIGHT_COLOR;
200}
201
202 /**
203当鼠标移出某个条目时,正常显示该条目
204*/
205 function unhighlightResult()
206 {
207 _unhighlightResult(this);
208}
209
210 function _unhighlightResult(item)
211 {
212 item.style.backgroundColor = DIV_BG_COLOR;
213}
214
215 /**
216显示/不显示下拉区
217*/
218 function showDiv (show)
219 {
220 var div = getDiv(divName);
221 if (show)
222 {
223 div.style.visibility = "visible";
224 }
225 else
226 {
227 div.style.visibility = "hidden";
228 }
229 //adjustiFrame();
230}
231
232 /**
233隐藏下拉区
234*/
235 function hideDiv ()
236 {
237 showDiv(false);
238}
239
240 /**
241调整IFrame的位置,这是为了解决div可能会显示在输入框后面的问题
242*/
243 function adjustiFrame()
244 {
245 // 如果没有IFrame,则创建之
246 if (!document.getElementById(ifName))
247 {
248 var newNode = document.createElement("iFrame");
249 newNode.setAttribute("id", ifName);
250 newNode.setAttribute("src", "javascript:false;");
251 newNode.setAttribute("scrolling", "no");
252 newNode.setAttribute("frameborder", "0");
253 document.body.appendChild(newNode);
254 }
255
256 iFrameDiv = document.getElementById(ifName);
257 var div = getDiv(divName);
258
259 // 调整IFrame的位置与div重合,并在div的下一层
260 try
261 {
262 iFrameDiv.style.position = "absolute";
263 iFrameDiv.style.width = div.offsetWidth;
264 iFrameDiv.style.height = div.offsetHeight;
265 iFrameDiv.style.top = div.style.top;
266 iFrameDiv.style.left = div.style.left;
267 iFrameDiv.style.zIndex = div.style.zIndex - 1;
268 iFrameDiv.style.visibility = div.style.visibility;
269 }
270 catch (e)
271 {
272 }
273}
274
275 /**
276文本输入框的onkeydown响应函数
277*/
278 function keypressHandler (evt)
279 {
280 // 获取对下拉区的引用
281 var div = getDiv(divName);
282
283 // 如果下拉区不显示,则什么也不做
284 if (div.style.visibility == "hidden")
285 {
286 return true;
287 }
288
289 // 确保evt是一个有效的事件
290 if (!evt && window.event)
291 {
292 evt = window.event;
293 }
294 var key = evt.keyCode;
295
296 var KEYUP = 38;
297 var KEYDOWN = 40;
298 var KEYENTER = 13;
299 var KEYTAB = 9;
300
301 // 只处理上下键、回车键和Tab键的响应
302 if ((key != KEYUP) && (key != KEYDOWN) && (key != KEYENTER) && (key != KEYTAB))
303 {
304 return true;
305 }
306
307 var selNum = getSelectedSpanNum(div);
308 var selSpan = setSelectedSpan(div, selNum);
309
310 // 如果键入回车和Tab,则选择当前选择条目
311 if ((key == KEYENTER) || (key == KEYTAB))
312 {
313 if (selSpan)
314 {
315 _selectResult(selSpan);
316 }
317 evt.cancelBubble = true;
318 return false;
319 }
320 else //如果键入上下键,则上下移动选中条目
321 {
322 if (key == KEYUP)
323 {
324 selSpan = setSelectedSpan(div, selNum - 1);
325 }
326 if (key == KEYDOWN)
327 {
328 selSpan = setSelectedSpan(div, selNum + 1);
329 }
330 if (selSpan)
331 {
332 _highlightResult(selSpan);
333 }
334 }
335
336 // 显示下拉区
337 showDiv(true);
338 return true;
339}
340
341 /**
342获取当前选中的条目的序号
343*/
344 function getSelectedSpanNum(div)
345 {
346 var count = -1;
347 var spans = div.getElementsByTagName("div");
348 if (spans)
349 {
350 for (var i = 0; i < spans.length; i++)
351 {
352 count++;
353 if (spans[i].style.backgroundColor != div.style.backgroundColor)
354 {
355 return count;
356 }
357 }
358 }
359
360 return -1;
361}
362
363 /**
364选择指定序号的结果条目
365*/
366 function setSelectedSpan(div, spanNum)
367 {
368 var count = -1;
369 var thisSpan;
370 var spans = div.getElementsByTagName("div");
371 if (spans)
372 {
373 for (var i = 0; i < spans.length; i++)
374 {
375 if (++count == spanNum)
376 {
377 _highlightResult(spans[i]);
378 thisSpan = spans[i];
379 }
380 else
381 {
382 _unhighlightResult(spans[i]);
383 }
384 }
385 }
386
387 return thisSpan;
388}
389
1
<
script language
=
"
javascript
"
src
=
"
lookup.js
"
><
/
script>
2 < script language = " javascript " >
3 mainLoop = function ()
4 {
5 val = escape(queryField.value);
6 if (lastVal != val)
7 {
8 var response = _Default.GetSearchItems(val);
9 showQueryDiv(response.value);
10lastVal = val;
11 }
12 setTimeout('mainLoop()', 100);
13 return true;
14 }
15 < / script>
由上述代码可以看到
mainLoop
函数每隔
100ms
会执行一次,它会判断当前文本输入框的值和上次提交查询的值是否相同,如果不同,它会重新向服务器发送请求进行查询,并且更新下拉区域的显示。2 < script language = " javascript " >
3 mainLoop = function ()
4 {
5 val = escape(queryField.value);
6 if (lastVal != val)
7 {
8 var response = _Default.GetSearchItems(val);
9 showQueryDiv(response.value);
10lastVal = val;
11 }
12 setTimeout('mainLoop()', 100);
13 return true;
14 }
15 < / script>
于此,一个基于 Ajax的自动完成功能就实现了。
本文借鉴于《 ajax web2.0快速入门与项目实践》。
这本书上还使用了控件将该功能进行了封装,这样要实现Ajax的自动完成功能就更加方便了。在此就不做过多解说。