zhang1x1 发表于 2013-2-6 10:14:54

类似google搜索提示支持键盘应用

代码从一位论坛老兄铁木箱子那里学来的,下面是记录一下自己用起来的方法。

首先建立一个js内容如下



/**
* Desc:该JS需要先导入../common/base.js
*/

/**
* 说明:
* 服务器返回的XML数据流要是如下的格式:
* <?xml version="1.0" encoding="gbk"?>
* <root>
*   <nodeName>条目一</nodeName>
*   <nodeName>条目二</nodeeName>
*   <nodeName>条目三</nodeName>
* </root>
* 上面的nodeName就是search中的nodeName参数。
*/

   function createXMLHttpRequest(){
            if(window.XMLHttpRequest) {
                XMLHttpReq = new XMLHttpRequest();
            }
            else if(window.ActiveXObject) {
                try {
                  XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                  try {
                        XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
                  } catch (e) {}
                }
            }
            return XMLHttpReq;
      }

var JSearcher = {

xmlHttp : null,                     // xmlHttpRequest对象
randName : 'jrandnum',            // 随机码的参数名称
_popup : null,                      // 提示框对象
_mouseOverColor : '#29cea3',      // 鼠标悬停时的背景颜色
_mouseOutColor : 'white',         // 鼠标离开时的背景颜色
_bgColor : 'white',               // 条目显示区的背景色
_tmpURL : '',                     // 上一个请求的地址
_tmpKey : '',                     // 上一次请求的关键字
_srcElt : null,                     // 触发时间的HTML元素
_tbodyID : '_$jst@#_$',             // 条目的表格体唯一ID

/**
* Desc:搜索的开始方法.附加该方法到指定input或textarea的onkeypress事件上即可。
* Para:urlStr      请求地址
*      inputObj      输入框对象
*      triggerKey    触发搜索的按键,比如说'a'。不设定将所有的按键都触发,
*                  可以设置为null或''
*      searchNum   需要显示的最多搜索条目数
*      nodeName      XML数据流中的节点名称
*/
search:function(urlStr, inputObj, triggerKey, searchNum, nodeName)
{

// 触发键控制,只有在输入框中按此键时才触发搜索查询
if (triggerKey != null && (typeof(triggerKey) == 'string' && triggerKey != '')) {
   if (event.keyCode != triggerKey.charCodeAt(0))return;
}

if (inputObj == null || typeof(inputObj) != 'object') {
   alert("Error: the object you set to parameter 'inputobj' is null!");
   return;
}
   
// 过滤回车选定重复显示的问题
if (event.keyCode == 13) return;

// 对同一地址,同一关键字不进行第二次请求
if (this._tmpURL == urlStr && this._tmpKey == inputObj.value) {
   this._showPopup();
   return;
} else {
   this._tmpURL = urlStr;
   this._tmpKey = inputObj.value;
}

// 设定触发该事件的源元素
this._srcElt = window.event.srcElement;

   

// 附加控制
var keypressFunc = inputObj.onkeydown;
inputObj.onkeydown = function() {
   JSearcher._selectKeys(inputObj);
   //if (typeof(keypressFunc) == 'function') keypressFunc();
}

// 发送请求

if (this.xmlHttp == null) this.xmlHttp = createXMLHttpRequest();
   
if (this.xmlHttp.readyState !=0 || this.xmlHttp.readyState != 4) {
   
      this.xmlHttp.abort();
}

try{
   with (this.xmlHttp) {
    // 加随机数防止缓存
    if (urlStr.indexOf("?") == -1) urlStr += "?";
    else urlStr += "&";
    urlStr += this.randName + Math.random() + "=" + Math.random();
   
   
    // 发送请求
    onreadystatechange = function (){
   //alert(JSearcher.xmlHttp);
            if (JSearcher.xmlHttp.readyState == 4 && JSearcher.xmlHttp.status == 200) {
               
                  JSearcher._JparseSearch(JSearcher.xmlHttp, inputObj, searchNum, nodeName);
            }
          }
    open("POST", urlStr, true);
    setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
    send(null);
   }
} catch (ex) {
   alert(ex);
}

},

/**
* Desc:设置全局变量属性
* Para:attrName      要设置的属性名称
*      attrValue       要设置的属性的值
*/
setGlobal:function(attrName, attrValue)
{
if (typeof(attrName) == 'undefined' || typeof(attrValue) == 'undefined') return;
switch (attrName) {
   case 'selectedColor' : this._mouseOverColor = attrValue;break;
   case 'unSelectedColor' : this._mouseOutColor = attrValue;break;
   case 'bgColor' : this._bgColor = attrValue;break;
}
},

/**
* Desc:解析服务器返回的XML数据流
   * Para:myXMLHttp      xmlHttpRequest对象
   *      obj            input框对象
   *      searchNum      搜索结果显示的最大条目数
*      nodeName         XML数据流中指定节点的名称
*/
_JparseSearch:function(myXMLHttp, obj, searchNum, nodeName)
{
if (myXMLHttp == null) {
   alert("Error: the xmlHttpRequest is null!");
   return;
}
var xmlStream = myXMLHttp.responseXML;
if (xmlStream == null) {
   alert("Error: the xml stream from server is null!");
   return;
}
var slist = xmlStream.getElementsByTagName(nodeName);
if (slist.length < 1) return;
if (obj.id == '') obj.id = '_$my#g' + Math.random();
this._tbodyID = this._tbodyID + Math.random();
var htmlStr = "<table width='100%' height='100%' border='0' cellspacing='0'"
               + " cellpadding='0' style='filter:alpha(opacity=80);"
               + "font-size:12px;'><tbody id='" + this._tbodyID + "'>";
for ( var i = 0 ; i < slist.length ; i ++) {
   var et = slist.item(i);
   
   if (i == searchNum) break;
   if (!et.hasChildNodes()) continue;
   htmlStr += "<tr onmouseout=\"this.style.backgroundColor='"
         + this._mouseOutColor + "'\" "
         + "onmouseover=\"this.style.backgroundColor='"
         + this._mouseOverColor + "'\"><td height='20' "
         + "onclick='JSearcher._setValue(\"" + obj.id + "\",\""
         + et.firstChild.nodeValue + "\")'>"
         + et.firstChild.nodeValue + "</td></tr>";
}
htmlStr += "</tbody></table>";
this._initPopup(obj, htmlStr);
this._showPopup();
},

/**
* Desc:按键操作检测
* Para:obj      input输入框对象
*/
_selectKeys:function(obj)
{
if ( this._popup.style.display == "none") return;

var code = event.keyCode;
var curRowIndex = 0;

var tbody = document.getElementById(this._tbodyID);
if (tbody != null && tbody.rows.length >= 1) {
   var et = null;
   for (var i = 0 ; i < tbody.rows.length ; i++) {
    et = tbody.rows;
    if (et.style.backgroundColor == this._mouseOverColor) {
   curRowIndex = i;
   break;
    }
   }
   if (code == 38) { // 上箭头
    tbody.rows.style.backgroundColor = this._mouseOutColor;
    if (curRowIndex == 0) {
   tbody.rows.style.backgroundColor = this._mouseOverColor;
    } else {
   tbody.rows.style.backgroundColor = this._mouseOverColor;
    }
   }
   if (code == 40) { // 下箭头
    tbody.rows.style.backgroundColor = this._mouseOutColor;
    if (curRowIndex == tbody.rows.length-1) {
   tbody.rows.style.backgroundColor = this._mouseOverColor;
    } else {
   tbody.rows.style.backgroundColor = this._mouseOverColor;
    }
   }
   if (code == 13 && et != null) { // 回车键
    this._setValue(obj.id, et.childNodes.firstChild.nodeValue);
   }
}
},

/**
* Desc:设定选中的值到输入框中
* Para:objID   输入框对象的唯一ID
*      sval      被选中的值
*/
_setValue:function(objID, sval)
{
var inputObj = document.getElementById(objID);
if (inputObj != null) {
   inputObj.value = sval;
   this._hidePopup();
   inputObj.focus();
}
},

/**
* Desc:初始化提示框
* Para:obj      input输入框对象
*      htmlStr    DIV中的HTML数据代码
*/
_initPopup:function(obj, htmlStr)
{
if (this._popup == null) {
   this._popup = document.createElement("div");
   this._popup.id = "_$myJSearcherID" + Math.random();
   this._popup.style.display = "none";
   this._popup.style.zIndex = "100";
   this._popup.style.border="solid black 1px";
   this._popup.style.position = "absolute";
   this._popup.style.backgroundColor = this._bgColor;
   document.body.appendChild(this._popup);
}

// 定位控制
var _objXY = this._srcElt.getBoundingClientRect(); // 确定触发源的真实位置
   
var _win = window;
var _top = window;
while(_top.parent.document != _top.document){
   _top = _top.parent;
}
var _leftM = _win.screenLeft - _top.screenLeft + 2; // 偏移量
var _topM = _win.screenTop - _top.screenTop + 2;
_leftM = _leftM == 2 ? 0 : _leftM;
_topM = _topM == 2 ? 0 : _topM;

var _divTop = _top.document.body.scrollTop + _topM + _objXY.bottom;
var _divLeft = _top.document.body.scrollLeft + _leftM + _objXY.left;
var _winSize = this._getClientWidthHeight(_top);
if((_divTop + this._popup.offsetHeight >= _winSize._height) &&
   (_winSize._height - _divTop <= _divTop-this._srcElt.offsetHeight)) {
   _divTop -= this._popup.offsetHeight - this._srcElt.offsetHeight - 3;
}

//this._popup.style.top = _divTop;
// this._popup.style.width = _objXY.right - _objXY.left;
//this._popup.style.left = _divLeft;
this._popup.style.width=obj.offsetWidth + "px";
var left = this._calculateOffset(obj, "offsetLeft");
var top = this._calculateOffset(obj, "offsetTop") + obj.offsetHeight;
this._popup.style.border = "black 1px solid";
this._popup.style.left = left + "px";
this._popup.style.top = top + "px";
//alert("---top--"+this._popup.style.top+"---width--"+this._popup.style.width+"---left--"+this._popup.style.left);
this._popup.innerHTML = htmlStr;
},

/**
* Desc:显示提示框
*/
_showPopup:function()
{
if (this._popup != null) {
   this._popup.style.display = "";
}
},

/**
* Desc:隐藏提示框
*/
_hidePopup:function()
{
if (this._popup != null) {
   this._popup.style.display = "none";
}
},

/**
* Desc:取得客户端屏幕的宽度和高度信息
*/
_getClientWidthHeight:function(win)
{
if(win==null){win=window;}
var cw = win.document.getElementsByTagName("html").clientWidth;
var ch = win.document.getElementsByTagName("html").clientHeight;
cw = (cw>0) ? cw : win.document.body.clientWidth;
ch = (ch>0) ? ch : win.document.body.clientHeight;
return {'_width':cw, '_height':ch};
},

/**
* Desc:计算显示位置
*/
_calculateOffset:function(field, attr){
var offset = 0;
            while(field) {
                offset +=field;
                field = field.offsetParent;
            }
      return offset;
}
};

window.document.onclick = function()
{
JSearcher._hidePopup();
}

只需在jsp页面引入上面js即可
jsp代码如下注意返回的提示信息要是xml

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%
String contextpath = request.getContextPath();
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
%>
<html>
    <head>
      <title>模拟google输入提示</title>
      <META http-equiv=Content-Type content="text/html; charset=UTF-8">
       <!--这里需要引入一个Base.js和上面我们创建的js(autosearch.js)-->
      <script   type="text/javascript" src="<%=contextpath%>/script/Base.js"></script>
      <script   type="text/javascript"src="<%=contextpath%>/script/autosearch.js"></script>
<script   type="text/javascript"src="<%=contextpath%>/script/testzw.js"></script>
    </head>
    <script language="javascript">
   
   

    </script>
   
    <body leftmargin="0" topmargin="0">
      <table style="BORDER-COLLAPSE: collapse" borderColor="#111111" cellspacing="0" cellpadding="2" width="400" bgcolor="#f5efe7" border="0">
            <tr>
                <td align="middle" bgcolor="#dbc2b0" height="19" colspan="3">
                  <b>商品信息搜索</b>
                </td>
            </tr>
            <tr>
                <td height="20">
                  输入品牌关键字:
                </td>
                <td align="center">
<!-- 这里是调用方法:具体参数涵义参考上面js说明 -->
                  <input type="text" size="15" id="names"   onkeyup="JSearcher.search('ConsumeCheckin.shtml?flag=yoyo&usercode='+this.value,this,'',10,'res')"style="height:20">
                  
                </td>
               
            </tr>
         
      </table>
    </body>
</html>



声明 代码是借来并非原创,写这篇文章的目的让大家知道怎么用起来
页: [1]
查看完整版本: 类似google搜索提示支持键盘应用