ice world

There is nothing too difficult if you put your heart into it.
posts - 104, comments - 103, trackbacks - 0, articles - 0

高仿Google Suggest & Baidu Suggest

Posted on 2011-04-24 03:41 IceWee 阅读(883) 评论(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>]&nbsp;&nbsp;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="&nbsp;手气不错&nbsp;" 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;">&copy; 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的控制台输出。

欢迎网友们多多交流!


只有注册用户登录后才能发表评论。


网站导航: