|  | 
				
					
	
		
			
 			Posted on 2011-04-24 03:41 IceWee  阅读(907) 评论(0)  编辑  收藏   所属分类: Javascript   
经常用谷歌百度的人会觉得他们自动提示下拉框很酷,而且用来起很方便。最近由于业务需求,我们也需要这样的功能,网络上搜刮了一下,但却遇不到自己满意的,于是决定取长补短,自己重构。由于平常很少写类似控件或小工具的脚本,顶多写点简单的校验脚本,所以写了这个东东花费了我3天时间,当然3天也不全是一直扑到它身上,毕竟还有其他的工作,通过这次练习,自己对protype的熟悉又更近了一步。 这个版本自己还算满意,可自定义的参数也开放了不少,主要是为用着方便着想嘛!没有引用外部css类,而是全写在脚本里,毕竟一个下拉提示框而已,并不是什么复杂的控件,也没必要再单独弄个css文件。 支持动态数据和静态数据两种方式,二者择一,动态数据通过传递url和参数名,静态数据通过传递数组,如果都传递则根据指定的是否是用动态数据参数来决定,如果没有设置该参数则使用静态数据。语言描述比较苍白,代码不多,但我这水平较浅,写出来也费劲心思,呵呵,见笑!下面将HTML和JS代码贴出: 下拉框外观完全仿照谷歌样式,包含边框以及选中项的背景色。至于关键字样式是仿照百度做的,谷歌关键字并没有处理,大家可以打开谷歌和百度比较一下区别。 界面截图:  
 Google.html 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <HTML>
 <HEAD>
 <TITLE>高仿Google Suggest & Baidu Suggest</TITLE>
 <META http-equiv="Content-Type" content="text/html; charset=GBK">
 <script type="text/javascript" src="google.suggest.js"></script>
 <script type="text/javascript">
 <!--
 var stringArray = new Array('java', 'JAVA游戏', 'java下载', 'javascript', 'javaeye', 'JAVA教程', 'java游戏下载', 'javascript教程', 'JAVA虚拟机', 'java正则表达式',
 '77元廉租房', '77元特惠房', '77元大床房', '77元特惠大床房', '77元 7天', '77元特惠房预订专区', '7天77元', '7天连锁酒店77元',
 '程序员', '程序员之家', '程序员考试', '程序员面试宝典', '程序员工资', '程序员的老婆是谁', '程序员论坛', '程序员修炼之道', '程序员杂志', '程序员招聘');
 var objectArray = new Array();
 var url = 'http://localhost:8080/google.suggest/servlet/getData?dataType=string';    // object or string
 
 function initObjectArray() {
 var id;
 var name;
 for (var i = 0; i < stringArray.length; ++i) {
 id = i+1;
 name = stringArray[i];
 objectArray[i] = {id: id, name: name};
 }
 }
 
 /**
 * 回调函数
 *
 * @param {Object} id 当为字符串数组时,没有值
 * @param {Object} name
 */
 function callback(id, name) {
 document.getElementById('span_id_value').innerHTML = id;
 document.getElementById('span_name_value').innerHTML = name;
 }
 
 window.onload = function() {
 var input = document.getElementById('search');
 input.blur();    // FireFox想聚焦必须先失去焦点
 input.focus();
 initObjectArray();
 
 var data = {
 input: input,    // 必需参数,可为输入框ID或者输入框对象
 isDynamicData: false,    //    可选参数,默认false,不指定则自动判断给定的数组参数与url,如果指定了动态或静态数据方式则相应参数为必填,如指定了true,则url必须有效,指定了false,则数组不能为空
 isObjectArray: false    ,    // 可选参数,默认false,使用的是否是对象数组或字符串数组,如果为对象数组要求属性名为id和name,如果不指定则默认使用字符串数组
 dataArray: stringArray,    // 与url二选一,字符串数组,如果数组内容不为空,同时又指定了url,则优先使用数组
 url: url,    // 与dataArray二选一,ajax动态获取数据的url
 paramName: 'keywords',    // 如果动态获取数据为必需参数,否则为可选参数
 maxShowRows: 20,    //    可选参数,下拉框最大显示行数,超出该值的数据将不被显示,默认值为30
 showText: 'Google Search', // 可选参数,默认显示在输入框中的文字,一般用于提示用户,如果不指定则默认为“”
 showTextOffsetLeft: 7,    // 可选参数 ,下拉列表文字内容与左侧的空白距离,默认值为0
 showTextColor: '',    // 可选参数,默认显示在输入框中的文字的颜色,默认颜色为灰色,值为“#999999”
 showTextFontStyle: '',    // 可选参数,默认显示在输入框中的文字的样式, 默认样式为斜体,值为“italic”
 focusItemBgColor: '',    // 可选参数,鼠标停留(mouseover)下拉框的背景色,同Google,值为“#D5E2FF”
 blurItemBgColor: '',    // 可选参数,鼠标划过(mouseout)下拉框的背景色,默认颜色为白色,值为 “#FFFFFF”
 suggestBorderColorLT: '',    // 可选参数, 下拉框左上的边框颜色,同Google,值为“#A2BFF0”, LT 含义为 left和top
 suggestBorderColorRB: '',    // 可选参数, 下拉框右下的边框颜色,同Google,值为“#558BE3”, RB含义为right和bottom
 itemFontSize: '',    //  可选参数,下拉框每一行的字体大小,如果未指定而且输入框也没设置字体大小则默认值为12pt,如果未指定,但输入框指定了字体大小,则自动使用输入框字体大小
 isSortData: '',    // 可选参数,是否将数据进行排序显示,默认不排序
 callback: callback,    // 可选参数,回调函数,参数为id和name,如果为对象数组ID有值,当用户鼠标点击或者按回车选择后触发该函数
 isCaseSensitive: true    // 可选参数,是否忽略查询英文字母大小写,默认为false,即不忽略,静态数据有效,动态数据该参数无效,而是由服务端处理逻辑决定
 }
 new googleSuggest(data).go();
 }
 //-->
 </script>
 <style type="text/css">
 <!--
 #search {
 background: #FFFFFF;
 border-width: 1px;
 border-style: solid;
 border-color: #CCCCCC #999999 #999999 #CCCCCC;
 font-size: 14pt;
 margin: 0px;
 padding: 5px 8px 0px 3px;
 color: #000000;
 height: 30px;
 }
 
 .lsbb {
 background: #eee;
 border: solid 1px;
 border-color: #ccc #999 #999 #ccc;
 height: 30px;
 display: inline-block;
 }
 
 .lsb {
 background: url('nav_logo66.png') bottom;
 border: none;
 color: #000;
 cursor: pointer;
 height: 30px;
 margin: 0;
 outline: 0;
 padding: 0 6px;
 width: auto;
 overflow: visible;
 font: 15px arial, sans-serif;
 vertical-align: top;
 }
 //-->
 </style>
 </HEAD>
 <BODY style="margin: 0; background-color: #FFFFFF; color: #000000;">
 <table cellSpacing="0" cellPadding="0" width="100%" height="24">
 <tr>
 <td>
 id:[<span id="span_id_value" style="text-align: center; width: 20px;"></span>]  name:[<span id="span_name_value" style="text-align: center; width: 150px;"></span>]
 </td>
 <td></td>
 <td>
 <DIV style="width: 100%; padding-top: 1px !important; text-align: right;">
 <span style="font-style: italic; color: #0000CC; padding-right: 5px;">高仿Google Suggest & Baidu Suggest</span>
 </DIV>
 </td>
 </tr>
 </table>
 <DIV style="position: absolute; right: 0px; width: 100%; top: 24px; height: 0; border-top: 1px solid #c9d7f1;"></DIV>
 <CENTER>
 <BR />
 <DIV><IMG id="logo" title="Google" border="0" alt="Google" src="logo_cn.png" width="276" height="110"><BR /><BR /></DIV>
 <TABLE cellSpacing="0" cellPadding="0">
 <TR vAlign="top">
 <TD align="center">
 <INPUT id="search" title="Google 搜索" size="57" /><BR /><BR /><BR />
 <SPAN class="ds">
 <SPAN class="lsbb"><INPUT class="lsb" value="Google 搜索" type="button" /></SPAN>
 </SPAN>
 <SPAN class="ds">
 <SPAN class="lsbb"><INPUT class="lsb" value=" 手气不错 " type="button" /></SPAN>
 </SPAN>
 </TD>
 </TR>
 </TABLE>
 <DIV style="font-size: 83%; min-height: 3.5em;"><BR>
 <DIV id="als"><FONT id="addlang" size="-1">请输入以下关键字进行测试:java 77元 程序员</FONT><BR /><BR /></DIV>
 </DIV>
 <SPAN id="footer">
 <CENTER id="fctr">
 <DIV style="font-size: 10pt;">
 <DIV style="margin: 19px auto; text-align: center;" id="fll">
 <a style="display: inline-block; margin: 0 12px;" href="mailto:icewee@tom.com?subject=Google Suggest">联系作者</a>
 <a style="display: inline-block; margin: 0 12px;" href="http://icewee.cnblogs.com" target="_blank">作者博客</a>
 </DIV>
 </DIV>
 <P style="color: rgb(118, 118, 118); font-size: 8pt;">© 2011 - <A href="javascript:void(0)">Icesoft</A></P>
 </CENTER>
 </SPAN>
 </CENTER>
 </BODY>
 </HTML>
 
 
 google.suggest.js 第一部分 
 
/*** This version of Software is free for using in non-commercial applications.
 * For commercial use please contact icewee@tom.com to obtain license
 * author: IceWee
 * blog: http://icewee.cnblogs.com
 * Date: 2011-04-25 0:58:54 (Mon, 25 Apri 2011)
 */
 function googleSuggest(data) {
 this.$settings = {
 input: null,
 url: null,
 paramName: null,
 dataArray: new Array(),
 maxShowRows: 30,
 showText: '',
 showTextColor: '#999999',
 showTextFontStyle: 'italic',
 showTextOffsetLeft: 0,
 focusItemBgColor: '#D5E2FF',
 blurItemBgColor: '#FFFFFF',
 suggestBorderColorLT: '#A2BFF0',
 suggestBorderColorRB: '#558BE3',
 isDynamicData: false,
 itemFontSize: '12pt',
 isSortData: true,
 isObjectArray: false,
 callback: null,
 isCaseSensitive: false
 }
 this.$isIE = true;
 this._copySettings(data);
 this.$suggest = null;    // suggest div
 this.$focusItemIndex = -1;
 this.$DOWN = '40';    // keyboard keyCode down
 this.$UP = '38';    // keyboard keyCode up
 this.$ENTER = '13';    // keyboard keyCode Enter
 this.$xmlHttp = null;    // ajax object
 this.$HTTP_STATE_UNINITIALIZED = 0;    // xmlHttpRequest object is not be initilaized
 this.$HTTP_STATE_LOADING = 1;
 this.$HTTP_STATE_LOADED = 2;
 this.$HTTP_STATE_INTERACTIVING = 3;
 this.$HTTP_STATE_COMPLETED = 4;
 this.$HTTP_STATUS_OK = 200;
 return this;
 }
 
 /**
 * @desc: working now!
 */
 googleSuggest.prototype.go = function() {
 if (this._isCanGo()) {
 this._initSuggest();
 this._initInput();
 } else {
 alert('initialize failed!');
 }
 };
 
 /**
 * @desc: copy params that user specified
 *
 * @param {Object} data
 */
 googleSuggest.prototype._copySettings = function(data) {
 if (typeof(data.input) == 'string')
 this.$settings.input = document.getElementById(data.input);
 else
 this.$settings.input = data.input;
 if (data.isSortData && data.isSortData == true) {
 this.$settings.isSortData = true;
 } else {
 this.$settings.isSortData = false;
 }
 if (data.isObjectArray && data.isObjectArray == true) {
 this.$settings.isObjectArray = true;
 } else {
 this.$settings.isObjectArray = false;
 }
 if (data.isCaseSensitive && data.isCaseSensitive == true) {
 this.$settings.isCaseSensitive = true;
 } else {
 this.$settings.isCaseSensitive = false;
 }
 if (data.isDynamicData && data.isDynamicData == true) {    // dynamic data
 this.$settings.isDynamicData = true;
 if (this._isNotBlank(data.url))
 this.$settings.url = data.url;
 if (this._isNotBlank(data.paramName))
 this.$settings.paramName = data.paramName;
 } else {
 this.$settings.isDynamicData = false;
 if (data.dataArray && data.dataArray.constructor == Array && data.dataArray.length > 0) {
 this.$settings.dataArray = data.dataArray;
 this._sortArray();    // sort the array or not
 }
 }
 if (this._isNotBlank(data.focusItemBgColor))
 this.$settings.focusItemBgColor = data.focusItemBgColor;
 if (this._isNotBlank(data.blurItemBgColor))
 this.$settings.blurItemBgColor = data.blurItemBgColor;
 if (this._isNotBlank(data.showText))
 this.$settings.showText = this._trim(data.showText);
 if (this._isNotBlank(data.showTextColor))
 this.$settings.showTextColor = data.showTextColor;
 if (this._isNotBlank(data.showTextFontStyle))
 this.$settings.showTextFontStyle = data.showTextFontStyle;
 if (this._isValidNum(data.maxShowRows))
 this.$settings.maxShowRows = data.maxShowRows;
 if (this._isValidNum(data.showTextOffsetLeft))
 this.$settings.showTextOffsetLeft = data.showTextOffsetLeft;
 if (this._isNotBlank(data.suggestBorderColorLT))
 this.$settings.suggestBorderColorLT = data.suggestBorderColorLT;
 if (this._isNotBlank(data.suggestBorderColorRB))
 this.$settings.suggestBorderColorRB = data.suggestBorderColorRB;
 if (this.$settings.input) {
 if (this._isNotBlank(data.itemFontSize))
 this.$settings.itemFontSize = data.itemFontSize;
 else if (this._isNotBlank(this._getInput().style.fontSize))
 this.$settings.itemFontSize = this._getInput().style.fontSize;
 }
 if (typeof(data.callback) == 'function'){
 this.$settings.callback = data.callback;;
 }else{
 if (this._isNotBlank(data.callback))
 this.$settings.callback = eval(data.callback);
 }
 this.$isIE = ((document.all) ? true : false) || navigator.userAgent.indexOf('MSIE') > 0;
 };
 
 /**
 * @desc: validate important params, whether can run script
 *
 * @return true or false
 */
 googleSuggest.prototype._isCanGo = function() {
 if (!this._getInput())    // invalid input
 return false;
 if (this.$settings.isDynamicData) {    // dynamic data
 if (this._isBlank(this.$settings.url) || this._isBlank(this.$settings.paramName))
 return false;
 } else {    // static data
 if (this.$settings.dataArray.length == 0) {
 return false;
 } else {
 // object array, formater eg:[{id: '1', name: 'java'}], only accept/process id and name property
 if (this.$settings.isObjectArray) {
 // here only validate the first element of array, so... I do not say whatever you know
 if (!this.$settings.dataArray[0].id || !this.$settings.dataArray[0].name)
 return false;
 }
 }
 }
 return true;
 };
 
 /**
 * @dese: sort the data array
 */
 googleSuggest.prototype._sortArray = function() {
 if (this.$settings.isSortData) {
 if (!this.$settings.isObjectArray) {    // string array
 this.$settings.dataArray.sort(function(a, b) {    // sort the array
 if (a.length > b.length)
 return 1;
 else if (a.length == b.length)
 return a.localeCompare(b);
 else
 return -1;
 });
 } else {    // object array
 if (this.$settings.dataArray[0].id && this.$settings.dataArray[0].name) {
 this.$settings.dataArray.sort(function(a, b) {    // sort the array
 if (a.name.length > b.name.length)
 return 1;
 else if (a.name.length == b.name.length)
 return a.name.localeCompare(b.name);
 else
 return -1;
 });
 }
 }
 }
 };
 
 /**
 * @desc: get current input
 *
 * @return current input object
 */
 googleSuggest.prototype._getInput = function() {
 return this.$settings.input;
 };
 
 /**
 * @desc: force blur the input
 */
 googleSuggest.prototype._forceBlurInput = function() {
 this._getInput().blur();
 };
 
 /**
 * @desc: initinalize the suggest
 */
 googleSuggest.prototype._initSuggest = function() {
 var input = this._getInput();
 var left = this._getAbsolutePosition(input)[0];
 var top = this._getAbsolutePosition(input)[1];
 var width = this._getWidthAndHeight(input)[0];
 var height = this._getWidthAndHeight(input)[1];
 this.$suggest = document.createElement('div');
 document.body.appendChild(this.$suggest);
 this.$suggest.style.position = 'absolute';
 this.$suggest.style.borderWidth = '1px';
 this.$suggest.style.borderStyle = 'solid';
 this.$suggest.style.borderLeftColor = this.$settings.suggestBorderColorLT;
 this.$suggest.style.borderTopColor = this.$settings.suggestBorderColorLT;
 this.$suggest.style.borderRightColor = this.$settings.suggestBorderColorRB;
 this.$suggest.style.borderBottomColor = this.$settings.suggestBorderColorRB;
 if (this.$isIE)
 this.$suggest.style.width = width + 'px';
 else
 this.$suggest.style.width = width - 2 + 'px';
 this.$suggest.style.left = left + 'px';
 this.$suggest.style.top = top + height - 1 + 'px';
 this.$suggest.style.display = 'none';
 };
 
 /**
 * @desc: init input and bind mouse and keyboard event
 */
 googleSuggest.prototype._initInput = function() {
 var input = this._getInput();
 input.suggest = this;
 input.value = this.$settings.showText;
 input.style.color = this.$settings.showTextColor;
 input.style.fontStyle = this.$settings.showTextFontStyle;
 input.onfocus = this._displaySuggest;
 input.onblur = this._inputBlur;
 input.onkeyup = this._catchKeyCode;
 };
 
 /**
 * @desc: current object may be input or suggest
 */
 googleSuggest.prototype._displaySuggest = function() {
 var o;
 if (this.$suggest) {    // suggest
 o = this;
 } else {
 o = this.suggest;    // input
 }
 if (!o.$settings.isDynamicData)    // static data
 o._staticSuggest();
 else
 o._dynamicSuggest();
 };
 
 /**
 * @desc: create suggest with the static data array
 */
 googleSuggest.prototype._staticSuggest = function() {
 this.$focusItemIndex = -1;
 var inputVal = this._getInput().value;
 inputVal = this._trim(inputVal);
 if (this._isNotBlank(inputVal)) {
 if (inputVal != this.$settings.showText) {
 this._getInput().style.color = '#000000';
 this._getInput().style.fontStyle = 'normal';
 this.$suggest.innerHTML = '';
 this._createSuggestItems(inputVal);
 if (this.$suggest.children.length > 0)
 this._showSuggest();
 else
 this._hideSuggest();
 } else {
 this._getInput().style.color = this.$settings.showTextColor;
 this._getInput().style.fontStyle = this.$settings.showTextFontStyle;
 this._getInput().value = '';
 this._hideSuggest();
 }
 } else {
 this._hideSuggest();
 }
 }
 
 /**
 * @desc: create suggest, with the url to get dynamic data array
 */
 googleSuggest.prototype._dynamicSuggest = function() {
 this.$focusItemIndex = -1;
 var inputVal = this._getInput().value;
 inputVal = this._trim(inputVal);
 if (this._isNotBlank(inputVal) ) {
 if (inputVal != this.$settings.showText) {
 this._getInput().style.color = '#000000';
 this._getInput().style.fontStyle = 'normal';
 this.$suggest.innerHTML = '';
 var url = this._constructUrl() + inputVal;
 var xmlHttp = this._getAjax();
 xmlHttp.suggest = this;
 xmlHttp.onreadystatechange = function() {
 try{
 if (xmlHttp.readyState == this.suggest.$HTTP_STATE_COMPLETED) {
 if (xmlHttp.status == this.suggest.$HTTP_STATUS_OK) {
 var array = xmlHttp.responseText;
 if (this.suggest._isNotBlank(array)) {
 this.suggest.$settings.dataArray = eval(array);
 this.suggest._sortArray();    // sort or not
 var size = 0;
 if (this.suggest.$settings.dataArray > this.suggest.$settings.maxShowRows + 1)
 size = this.suggest.$settings.maxShowRows + 1;
 else
 size = this.suggest.$settings.dataArray.length;
 var o, item;
 if (this.suggest.$settings.isObjectArray) {
 for (var i = 0; i < size; i++) {
 o = this.suggest.$settings.dataArray[i];
 if (typeof(o) == 'object') {
 if (!o.id && !o.name) {
 alert('Invalid format! The object must has id and name property, eg: [{id: 1, name: \'peter\'}, ...]');
 this.suggest._forceBlurInput();
 break;
 } else {
 item = this.suggest._createSuggestItem(o.name, inputVal);
 this.suggest.$suggest.appendChild(item);
 }
 } else {
 alert('Invalid format! Correct format is like this [{id: 1, name: \'peter\'}, {id: \'admin\', name: \'administrator\'}]');
 this.suggest._forceBlurInput();
 break;
 }
 }
 } else {    // string array
 for (var i = 0; i < size; i++) {
 o = this.suggest.$settings.dataArray[i];
 if (typeof(o) == 'string') {
 item = this.suggest._createSuggestItem(o, inputVal);
 this.suggest.$suggest.appendChild(item);
 } else {
 alert('Invalid format! Correct format is like this [\'java\', \'javascript\', \'javaeye\']');
 this.suggest._forceBlurInput();
 break;
 }
 }
 }
 if (this.suggest.$suggest.children.length > 0)
 this.suggest._showSuggest();
 else
 this.suggest._hideSuggest();
 } else {
 this.suggest._hideSuggest();
 }
 }
 }
 } catch (e) {alert(e);}
 }
 xmlHttp.open('GET', url, true);
 xmlHttp.send(null);
 } else {
 this._getInput().style.color = this.$settings.showTextColor;
 this._getInput().style.fontStyle = this.$settings.showTextFontStyle;
 this._getInput().value = '';
 this._hideSuggest();
 }
 } else {
 this._hideSuggest();
 }
 }
   google.suggest.js 第二部分 
 
/*** @desc: create the items show in the suggest, this method is used to static data, js fiter
 *
 * @param {Object} inputVal, input keywords
 */
 googleSuggest.prototype._createSuggestItems = function(inputVal) {
 var size = 0;
 if (this.$settings.dataArray > this.$settings.maxShowRows + 1)
 size = this.$settings.maxShowRows + 1;
 else
 size = this.$settings.dataArray.length;
 var reg = this._getRegExps(inputVal);
 var o, item;
 if (this.$settings.isObjectArray) {
 for (var i = 0; i < size; i++) {
 o = this.$settings.dataArray[i];
 if (typeof(o) == 'object') {
 if (!o.id && !o.name) {
 alert('Invalid format! The object must has id and name property, eg: [{id: 1, name: \'peter\'}, ...]');
 this._forceBlurInput();
 break;
 } else {
 item = this._createSuggestItem(o.name, inputVal);
 this.$suggest.appendChild(item);
 }
 } else {
 alert('Invalid format! Correct format is like this [{id: 1, name: \'peter\'}, {id: \'admin\', name: \'administrator\'}]');
 this._forceBlurInput();
 break;
 }
 }
 } else {    // string array
 for (var i = 0; i < size; i++) {
 o = this.$settings.dataArray[i];
 if (typeof(o) == 'string') {
 if (o.match(reg)) {
 item = this._createSuggestItem(o, inputVal);
 this.$suggest.appendChild(item);
 }
 } else {
 alert('Invalid format! Correct format is like this [\'java\', \'javascript\', \'javaeye\']');
 this._forceBlurInput();
 break;
 }
 }
 }
 };
 
 /**
 * @desc: create a item that show in suggest
 *
 * @param {Object} value, one value of the data array
 * @param {Object} inputVal, input keywords
 * @return item
 */
 googleSuggest.prototype._createSuggestItem = function(value, inputVal) {
 var v = value.replace(inputVal, '<span style="font-weight: normal;">' + inputVal + '</span>');
 var item = document.createElement('div');
 item.innerHTML = v;
 item.style.color = '#000000';
 item.style.backgroundColor = this.$settings.blurItemBgColor;
 item.style.fontWeight = 'bold';
 item.style.fontSize = this.$settings.itemFontSize;
 item.style.paddingLeft = this.$settings.showTextOffsetLeft + 'px';
 item.onmouseover = this._focusItem;
 item.onmouseout = this._blurItem;
 item.onmousedown = this._returnSelectedItem;
 item.suggest = this;
 return item;
 };
 
 /**
 * @desc: current object is suggest item(eg:<div>java</div>)
 */
 googleSuggest.prototype._focusItem = function() {
 this.style.backgroundColor = this.suggest.$settings.focusItemBgColor;
 };
 
 /**
 * @desc: return a Regular Expressions used to match keywords
 *
 * @param {Object} value, string
 * @return regexps
 */
 googleSuggest.prototype._getRegExps = function(value) {
 if (this.$settings.isCaseSensitive)
 return new RegExp(value, 'i');
 else
 return new RegExp(value);
 };
 
 /**
 * @desc: current object is suggest item(eg:<div>xxx</div>)
 */
 googleSuggest.prototype._blurItem = function() {
 this.style.backgroundColor = this.suggest.$settings.blurItemBgColor;
 };
 
 /**
 * @desc: current object is suggest item(eg:<div>javascript</div>)
 */
 googleSuggest.prototype._returnSelectedItem = function() {
 var name = this.innerHTML;
 var breg = new RegExp('<span style="font-weight: normal;">', 'i');    // <META content="IE=9" http-equiv="X-UA-Compatible">
 var mreg = new RegExp('<span style="font-weight: normal">', 'i');    // common, must remove ';'
 var ereg = new RegExp('</span>', 'i');
 name = name.replace(breg, '');
 name = name.replace(mreg, '');
 name = name.replace(ereg, '');
 this.suggest._getInput().value = name;
 var id = this.suggest._getIdbyName(name);
 if (this.suggest.$settings.callback)    // callback function
 this.suggest.$settings.callback(id, name);
 this.suggest._forceBlurInput();
 this.suggest._hideSuggest();
 };
 
 /**
 * @desc: whether the suggest is hide
 *
 * @return true of false
 */
 googleSuggest.prototype._isSuggestHide = function() {
 return this.$suggest.style.display == 'none';
 };
 
 /**
 * @desc: current object may be input or suggest, show the suggest
 */
 googleSuggest.prototype._showSuggest = function() {
 if (this.$suggest)    // suggest
 this.$suggest.style.display = 'block';
 else    // input
 this.suggest.$suggest.style.display = 'block';
 };
 
 /**
 * @desc: current object may be input or suggest, hide the suggest
 */
 googleSuggest.prototype._hideSuggest = function() {
 var o;
 if (this.$suggest) {    // suggest
 o = this;
 } else {    // input
 o = this.suggest;
 }
 o.$suggest.style.display = 'none';
 };
 
 /**
 * @desc: current object is input, when the input is blur that should be do?
 */
 googleSuggest.prototype._inputBlur = function() {
 this.suggest._hideSuggest();
 var inputVal = this.value;
 if (this.suggest._isBlank(inputVal)) {
 this.value = this.suggest.$settings.showText;
 this.style.color = this.suggest.$settings.showTextColor;
 this.style.fontStyle = this.suggest.$settings.showTextFontStyle;
 }
 };
 
 /**
 * @desc: current object is input, catch the keyboard event, judge to show or hide suggest
 */
 googleSuggest.prototype._catchKeyCode = function() {
 var keyCode = 0;
 if (this.suggest.$isIE) {
 var keyCode = event.keyCode;
 if (keyCode == this.suggest.$DOWN || keyCode == this.suggest.$UP) {    // down or up
 var isUp = true;
 if (keyCode == this.suggest.$DOWN)    // down
 isUp = false;
 this.suggest._changeFocusItem(isUp);
 } else if (keyCode == this.suggest.$ENTER) {
 this.suggest._catchEnter();
 } else {
 this.suggest._displaySuggest();
 }
 } else {
 this.suggest._displaySuggest();
 }
 };
 
 /**
 * @desc: used to catch enter event
 */
 googleSuggest.prototype._catchEnter = function() {
 var name = this._getInput().value;
 var id = this._getIdbyName(name);
 if (this.$settings.callback)    // callback function
 this.$settings.callback(id, name);
 this._forceBlurInput();
 this._hideSuggest();
 }
 
 /**
 * @desc: change the focus item and change the input text's style that show in the suggest
 *
 * @param {Object} isUp, keyboard event, up or down
 */
 googleSuggest.prototype._changeFocusItem = function(isUp) {
 if (this._isSuggestHide()) {
 this._showSuggest();
 } else {
 if (isUp)
 this.$focusItemIndex--;
 else
 this.$focusItemIndex++;
 }
 var maxIndex = this.$suggest.children.length - 1;
 if (this.$focusItemIndex < 0) {
 this.$focusItemIndex = maxIndex;
 }
 if (this.$focusItemIndex > maxIndex) {
 this.$focusItemIndex = 0;
 }
 var breg = new RegExp('<span style="font-weight: normal;">', 'i');    // <META content="IE=9" http-equiv="X-UA-Compatible">
 var mreg = new RegExp('<span style="font-weight: normal">', 'i');    // common, must remove ';'
 var ereg = new RegExp('</span>', 'i');
 var text;
 for (var i = 0; i <= maxIndex; i++) {
 if (i == this.$focusItemIndex) {
 text = this.$suggest.children[i].innerHTML;
 text = text.replace(breg, '');
 text = text.replace(mreg, '');
 text = text.replace(ereg, '');
 this._getInput().value = text;
 this.$suggest.children[i].style.backgroundColor = this.$settings.focusItemBgColor;
 } else {
 this.$suggest.children[i].style.backgroundColor = this.$settings.blurItemBgColor;
 }
 }
 };
 
 /**
 * @desc: get a html element's absolute position
 *
 * @param {Object} o, html element
 * @return array, value 1 is x coordinate and value 2 is y coordinate
 */
 googleSuggest.prototype._getAbsolutePosition = function(o) {
 var array = new Array();
 var top = 0, left = 0;
 do {
 top += o.offsetTop;
 left += o.offsetLeft;
 } while (o = o.offsetParent);
 array[0] = left;
 array[1] = top;
 return array;
 };
 
 /**
 * @desc: get a html element's width and height
 *
 * @param {Object} o, html element
 * @return array that first value is width and second value is height
 */
 googleSuggest.prototype._getWidthAndHeight = function(o) {
 var array = new Array();
 array[0] = o.offsetWidth;
 array[1] = o.offsetHeight;
 return array;
 };
 
 /**
 * @desc: trim a string
 *
 * @param {Object} string
 * @return string that remove the left space and right space, space(space and tab)
 */
 googleSuggest.prototype._trim = function(string) {
 return string.replace(/(^\s*)|(\s*$)/g, '');
 };
 
 /**
 * @desc: validate a string is null or ''
 *
 * @param {Object} string
 * @return true if is not '' or undefined, else false
 */
 googleSuggest.prototype._isValidString = function(string) {
 if (string && this._trim(string))
 return true;
 return false;
 }
 
 /**
 * @desc: validate number
 *
 * @param {Object} num
 * @return true if is valid number, else false
 */
 googleSuggest.prototype._isValidNum = function(num) {
 if (!isNaN(parseInt(num)))
 return true;
 return false;
 }
 
 /**
 * @desc: get an ajax object
 *
 * @return ajax object, this.$xmlHttp or new XMLHttpRequest
 */
 googleSuggest.prototype._getAjax = function() {
 if (!this.$xmlHttp) {
 this.$xmlHttp = this._getXMLHttpRequest();
 }
 if (this.$xmlHttp.readyState != this.$HTTP_STATE_COMPLETED) {
 return this._getXMLHttpRequest();
 }
 return this.$xmlHttp;
 };
 
 /**
 * @desc: create a XMLHttpRequest object
 *
 * @return a new XMLHttpRequest object
 */
 googleSuggest.prototype._getXMLHttpRequest = function() {
 var xmlHttp;
 if (window.XMLHttpRequest) {
 xmlHttp = new XMLHttpRequest();
 } else if (window.ActiveXobject) {
 try {
 xmlHttp = new ActiveXobject('MSXML2XMLHTTP');
 } catch (e){
 try {
 xmlHttp = new ActiveXobject('Microsoft.XMLHttp');
 } catch (e){}
 }
 }
 return xmlHttp;
 }
 
 /**
 * @desc: construct the full url with the user specified url and param name
 *
 * @return full url
 */
 googleSuggest.prototype._constructUrl = function() {
 var url = this.$settings.url;
 var paramName = this.$settings.paramName;
 if (url.indexOf('?') == -1)
 url += '?' + paramName + '=';
 else
 url += '&' + paramName + '=';
 return url;
 };
 
 /**
 * @desc: so... name must be unique, else will be wrong, see below you will be understand
 *
 * @param {Object} name, object array name
 * @return object array id value
 */
 googleSuggest.prototype._getIdbyName = function(name) {
 var id = null;
 var array = this.$settings.dataArray;
 for (var i = 0; i < array.length; ++i) {
 if (array[i].name == name)
 return array[i].id;
 }
 return id;
 }
 
 /**
 * blank means null/undefined/''/tab
 *
 * @param {Object} string
 * @return true or false
 */
 googleSuggest.prototype._isBlank = function(string) {
 if (string == undefined)    // null or un init
 return true;
 if (this._trim(string) == '')
 return true;
 return false;
 }
 
 /**
 * not blank
 *
 * @param {Object} string
 * @return true or false
 */
 googleSuggest.prototype._isNotBlank = function(string) {
 return !this._isBlank(string);
 }
   GetDataServlet.java 
 
package bing;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
 * Ajax获取模拟数据处理类
 *
 * @author Bing
 * @date 2011-4-22
 *
 */
 public class GetDataServlet extends HttpServlet {
 
 private static final long serialVersionUID = -5467391979358615867L;
 private String[] datas = { "JAVA", "JAVA游戏", "JAVA下载", "javascript",
 "javaeye", "JAVA教程", "java游戏下载", "javascript教程", "JAVA虚拟机",
 "JAVA正则表达式", "77元廉租房", "77元特惠房", "77元大床房", "77元特惠大床房", "77元 7天",
 "77元特惠房预订专区", "7天77元", "7天连锁酒店77元", "程序员", "程序员之家", "程序员考试",
 "程序员面试宝典", "程序员工资", "程序员的老婆是谁", "程序员论坛", "程序员修炼之道", "程序员杂志",
 "程序员招聘" };
 private List<Bean> beans = new ArrayList<Bean>();
 
 public GetDataServlet() {
 super();
 initializeBeans();
 }
 
 public void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 response.setContentType("text/html;charset=GBK");
 response.setCharacterEncoding("GBK");
 String dataType = request.getParameter("dataType");
 String keywords = request.getParameter("keywords");
 String dataString = "";
 if ("object".equals(dataType)) {
 dataString = getObjectArray(keywords);
 }else {
 dataString = getStringArray(keywords);
 }
 response.getWriter().print(dataString);
 }
 
 public void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 doGet(request, response);
 }
 
 /**
 * 字符串数组
 *
 * format: ['java', 'javascript', 'javaeye']
 *
 * @param keywords
 * @return
 */
 private String getStringArray(String keywords) {
 System.out.println("keywords: [" + keywords + "]");
 String stringArray = "";
 if (keywords != null && !"".equals(keywords)) {
 keywords = keywords.toLowerCase();
 StringBuffer buffer = new StringBuffer();
 for (String data : datas) {
 data = data.toLowerCase();
 if (data.indexOf(keywords) != -1)
 buffer.append("'").append(data).append("'").append(", ");
 }
 stringArray = buffer.toString();
 if (!"".equals(stringArray)) {
 stringArray = stringArray.substring(0, stringArray.lastIndexOf(", "));
 stringArray = "[" + stringArray + "]";
 }
 System.out.println("返回数据为字符串数组,内容:" + stringArray);
 }
 return stringArray;
 }
 
 /**
 * 对象数组(如果使用JSON就方便多了)
 *
 * format: [{id: '1', name: 'java'}, {id: '2', name: 'javascript'}]
 *
 * @param keywords
 * @return
 */
 private String getObjectArray(String keywords) {
 keywords = keywords.toLowerCase();
 StringBuffer buffer = new StringBuffer();
 for (Bean bean : beans) {
 String id = bean.getId();
 String name = bean.getName();
 String temp = bean.getName().toLowerCase();
 if (temp.indexOf(keywords) != -1)
 buffer.append("{").append("id: '").append(id).append("', name: '").append(name).append("'}, ");
 }
 String objectArray = buffer.toString();
 if (!"".equals(objectArray)) {
 objectArray = objectArray.substring(0, objectArray.lastIndexOf(", "));
 objectArray = "[" + objectArray + "]";
 }
 System.out.println("返回数据为对象数组,内容:" + objectArray);
 return objectArray;
 }
 
 private void initializeBeans () {
 for (int i = 0; i < datas.length; i++) {
 beans.add(new Bean(String.valueOf(i), datas[i]));
 }
 }
 
 }
   Bean.java 
 
package bing;
 public class Bean {
 
 private String id;
 private String name;
 
 public Bean() {
 super();
 }
 
 public Bean(String id, String name) {
 super();
 this.id = id;
 this.name = name;
 }
 
 public String getId() {
 return id;
 }
 
 public void setId(String id) {
 this.id = id;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 }
   web.xml 
 
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <servlet>
 <description>get Google suggest data</description>
 <display-name>GetData</display-name>
 <servlet-name>GetDataServlet</servlet-name>
 <servlet-class>bing.GetDataServlet</servlet-class>
 </servlet>
 
 <servlet-mapping>
 <servlet-name>GetDataServlet</servlet-name>
 <url-pattern>/servlet/getData</url-pattern>
 </servlet-mapping>
 <welcome-file-list>
 <welcome-file>Google.html</welcome-file>
 </welcome-file-list>
 </web-app>
   不满意的地方是没有弄好火狐的键盘事件,即上下键或者回车键,都不知道怎么捕捉,网上搜索了下,不过都不怎么好使,就放弃了。 当前默认是使用静态数据,如果部署到Tomcat中后,可将Google.html中的 isDynamicData: false  改为true即可,之后可以观察Tomcat的控制台输出。 欢迎网友们多多交流! 
	    
    
 |