用JQuery实现的类似GOOGLE\BAIDU搜索框的提示功能.

程序在一个页面只能创建一个提示搜索框,因为对js也不熟,所以还不知道怎么解决...

继续改进版,支持多个输入框!初步测试没发现问题,欢迎大家一起测试改进!!!

autopoint.js代码:


/* 
   
 * @date: 2010-5-22 21:42:15
 * @author: 胡灵伟
 * Depends:
 * jquery.js
 *
 * function:类似GOOGLE搜索框提示功能
 * use:$("#input1, #input2").autopoint({url:"url", submit:["submit1", "submit2"]});
 * 对所有需要自动提示功能的输入框对象使用autopoint方法,
 * url为ajax提交的url,submit为输入框enter键提交的action
 
   */ 
   
( 
   function 
   ($) {
 $.fn.autopoint  
   = 
     
   function 
    (options) {
 
   var 
    bt  
   = 
    $.browser;
 
   // 
   根据浏览器设定不同属性 
   
 
    dialect  
   = 
    bt.msie 
   ? 
   {
 topoffset: 
   5 
   , 
   // 
   提示框top属性与输入框偏移 
   
 
    widthoffset: 
   6 
   // 
   提示框width属性与输入框偏移  
   
 
    }:bt.mozilla 
   ? 
   {
 topoffset: 
   5 
   ,
 widthoffset: 
   2 
   
 }:bt.safari 
   ? 
   {
 topoffset: 
   6 
   ,
 widthoffset: 
   2 
   
 }:bt.opera 
   ? 
   {
 topoffset: 
   5 
   ,
 widthoffset: 
   2 
   
 }:{
 topoffset: 
   5 
   ,
 widthoffset: 
   2 
   
 };
 defaults  
   = 
    {
 url:options.url,
 keyUp :  
   38 
   , 
   // 
   向上方向键 
   
 
    keyDown :  
   40 
   , 
   // 
   向下方向键 
   
 
    keyEnter :  
   13 
   , 
   // 
   回车键 
   
 
    listHoverCSS :  
   ' 
   jhover 
   ' 
   , 
   // 
   提示框列表鼠标悬浮的样式 
   
 
    tpl :  
   ' 
   <div class="list"><div class="word">{word}</div><div class="view">{view}</div></div> 
   ' 
   ,
 submit:options.submit
 };
 
   var 
    originalVal  
   = 
     
   new 
    Array();
 
   var 
    lastVal  
   = 
     
   new 
    Array();
 
   var 
    options  
   = 
    $.extend(defaults, $.extend(dialect, options));
 
   var 
    dropDiv  
   = 
    $( 
   ' 
   <div></div> 
   ' 
   ).addClass( 
   ' 
   dropDiv 
   ' 
   ).appendTo( 
   ' 
   body 
   ' 
   );
 
   return 
     
   this 
   .each( 
   function 
   (i){
 
   var 
    pa  
   = 
    $( 
   this 
   );
 $( 
   this 
   ).bind( 
   ' 
   keydown 
   ' 
   ,  
   function 
   (event){
 
   if 
    (dropDiv.css( 
   ' 
   display 
   ' 
   )  
   != 
     
   ' 
   none 
   ' 
   ) { 
   // 
   当提示层显示时才对键盘事件处理 
   
 
     
   var 
    currentList  
   = 
    dropDiv.find( 
   ' 
   . 
   ' 
     
   + 
    options.listHoverCSS);
 
   if 
    (event.keyCode  
   == 
    options.keyDown) { 
   // 
   如果按的是向下方向键 
   
 
     
   if 
    (currentList.length  
   == 
     
   0 
   ) {
 originalVal[i]  
   = 
    $( 
   this 
   ).val();
 
   // 
   如果提示列表没有一个被选中,则将列表第一个选中 
   
 
    $( 
   this 
   ).val(getPointWord(dropDiv.find( 
   ' 
   .list:first 
   ' 
   )
 .mouseover()));
 }  
   else 
     
   if 
    (currentList.next().length  
   == 
     
   0 
   ) {
 
   // 
   如果是最后一个被选中,则取消选中,即可认为是输入框被选中 
   
 
    unHoverAll();
 $( 
   this 
   ).val(originalVal[i]);
 }  
   else 
    {
 unHoverAll();
 
   // 
   将原先选中列的下一列选中 
   
 
     
   if 
    (currentList.next().length  
   != 
     
   0 
   )
 $( 
   this 
   ).val(getPointWord(currentList.next()
 .mouseover()));
 }
 
   return 
     
   false 
   ;
 }  
   else 
     
   if 
    (event.keyCode  
   == 
    options.keyUp) { 
   // 
   如果按的是向上方向键 
   
 
     
   if 
    (currentList.length  
   == 
     
   0 
   ) {
 originalVal[i]  
   = 
    $( 
   this 
   ).val();
 $( 
   this 
   ).val(getPointWord(dropDiv.find( 
   ' 
   .list:last 
   ' 
   )
 .mouseover()));
 }  
   else 
     
   if 
    (currentList.prev().length  
   == 
     
   0 
   ) {
 unHoverAll();
 $( 
   this 
   ).val(originalVal[i]);
 }  
   else 
    {
 unHoverAll();
 
   if 
    (currentList.prev().length  
   != 
     
   0 
   )
 $( 
   this 
   ).val(getPointWord(currentList.prev()
 .mouseover()));
 }
 
   return 
     
   false 
   ;
 } 
   else 
     
   if 
   (event.keyCode  
   == 
    options.keyEnter) {
 
   // 
   console.debug(currentList.length); 
   
 
     
   if 
   (currentList.length  
   == 
     
   0 
   ) 
 
   if 
   (options.submit[i]) {
 $( 
   ' 
   # 
   ' 
   + 
   options.submit[i]).submit();
 }
 dropDiv.empty().hide();
 
   return 
   ;
 }
 } 
   else 
     
   if 
   (event.keyCode  
   == 
    options.keyEnter)
 
   // 
   console.debug(options.submit[i]); 
   
 
     
   if 
   (options.submit[i]) {
 $( 
   ' 
   # 
   ' 
   + 
   options.submit[i]).submit();
 
   return 
   ;
 }
 }).bind( 
   ' 
   keyup 
   ' 
   ,  
   function 
   (event){
 
   // 
   输入框值没有改变返回 
   
 
     
   if 
    ($( 
   this 
   ).val()  
   == 
    lastVal[i])
 
   return 
   ;
 
   // 
   当按键弹起记录输入框值,以方便查看键值有没有变 
   
 
    lastVal[i]  
   = 
    $( 
   this 
   ).val();
 
   // 
   输入框值变为空返回 
   
 
     
   if 
   ($( 
   this 
   ).val()  
   == 
     
   '' 
   ){
 dropDiv.empty().hide();
 
   return 
   ;
 }
 
   // 
   如果按下的向上或是向下键,说明在选择 
   
 
     
   if 
   (event.keyCode  
   == 
    options.keyUp 
   || 
   event.keyCode  
   == 
    options.keyDown)  
   return 
   ;
 
   // 
   输入框中值有变化,发送请求 
   
 
    getData(pa, $( 
   this 
   ).val());
 }).bind( 
   ' 
   blur 
   ' 
   ,  
   function 
   (){
 
   // 
   输入框失去焦点隐藏提示框,mousedown比 
   
 
     
   // 
   blur优先触发所以先处理选择提示框的内容 
   
 
    dropDiv.empty().hide();
 });

 
   /* 
   *处理ajax返回成功的方法* 
   */ 
   
 handleResponse  
   = 
     
   function 
   (parent, json) {
 
   var 
    isEmpty  
   = 
     
   true 
   ;
 
   for 
   ( 
   var 
    o  
   in 
    json){
 
   if 
   (o  
   == 
     
   ' 
   data 
   ' 
   ) isEmpty  
   = 
     
   false 
   ;
 }
 
   if 
   (isEmpty) {
 
   // 
   showError("返回数据格式错误,请检查请求URL是否正确!"); 
   
 
    dropDiv.empty().hide();
 
   return 
   ;
 }
 
   if 
   (json[ 
   ' 
   data 
   ' 
   ].length  
   == 
     
   0 
   ) {
 
   // 
   返回数据为空 
   
 
    dropDiv.empty().hide();
 
   return 
   ;
 }
 refreshDropDiv(parent, json);
 dropDiv.show();
 };
 
   /* 
   *处理ajax失败的方法* 
   */ 
   
 handleError  
   = 
     
   function 
   (error) {
 dropDiv.empty().hide();
 showError( 
   " 
   请求失败! 
   " 
   + 
   arguments[ 
   1 
   ]);
 };
 showError  
   = 
     
   function 
   (error){
 
   // 
   alert(error); 
   
 
    };
 
   /* 
   *通过ajax返回json格式数据生成用来创建dom的字符串* 
   */ 
   
 render  
   = 
     
   function 
   (parent, json) {
 
   var 
    res  
   = 
    json[ 
   ' 
   data 
   ' 
   ]  
   || 
    json;
 
   var 
    appendStr  
   = 
     
   '' 
   ;
 
   // 
   用json对象中内容替换模版字符串中匹配/\{([a-z]+)\}/ig的内容,如{word},{view} 
   
 
     
   for 
    (  
   var 
    i  
   = 
     
   0 
   ; i  
   < 
    res.length; i 
   += 
   1 
   ) {
 appendStr  
   += 
    options.tpl.replace( 
   / 
   \{([a-z]+)\} 
   / 
   ig,  
   function 
   (m, n) {
 
   return 
    res[i][n];
 });
 }
 jebind(parent, appendStr);
 };
 
   /* 
   *将新建dom对象插入到提示框中,并重新绑定mouseover事件监听* 
   */ 
   
 jebind  
   = 
     
   function 
   (parent, a) {
 dropDiv.append(a);
 dropDiv.find( 
   ' 
   .list 
   ' 
   ).each( 
   function 
   () {
 $( 
   this 
   ).unbind( 
   ' 
   mouseover 
   ' 
   ).mouseover( 
   function 
   () {
 unHoverAll();
 $( 
   this 
   ).addClass(options.listHoverCSS);
 }).unbind( 
   ' 
   mousedown 
   ' 
   ).mousedown( 
   function 
   (){
 parent.val(getPointWord($( 
   this 
   )));
 dropDiv.empty().hide();
 parent.focus();
 });
 });
 };
 
   /* 
   *将提示框中所有列的hover样式去掉* 
   */ 
   
 unHoverAll  
   = 
     
   function 
   () {
 dropDiv.find( 
   ' 
   .list 
   ' 
   ).each( 
   function 
   () {
 $( 
   this 
   ).removeClass(options.listHoverCSS);
 });
 };
 
   /* 
   *在提示框中取得当前选中的提示关键字* 
   */ 
   
 getPointWord  
   = 
     
   function 
   (p) {
 
   return 
    p.find( 
   ' 
   div:first 
   ' 
   ).text();
 };
 
   /* 
   *刷新提示框,并设定样式* 
   */ 
   
 refreshDropDiv  
   = 
     
   function 
   (parent, json) {
 
   var 
    left  
   = 
    parent.offset().left;
 
   var 
    height  
   = 
    parent.height();
 
   var 
    top  
   = 
    parent.offset().top  
   + 
    options.topoffset  
   + 
    height;
 
   var 
    width  
   = 
    options.width  
   || 
    (parent.width() 
   + 
   options.widthoffset)  
   + 
     
   ' 
   px 
   ' 
   ;
 dropDiv.empty();
 dropDiv.css( {
 
   // 
   'border' : '1px solid #999', 
   
 
     
   ' 
   left 
   ' 
    : left,
 
   ' 
   top 
   ' 
    : top,
 
   ' 
   width 
   ' 
    : width
 });
 render(parent, json);
 
   // 
   防止ajax返回之前输入框失去焦点导致提示框不消失 
   
 
    parent.focus();
 };
 
   /* 
   *通过ajax向服务器请求数据* 
   */ 
   
 getData  
   = 
     
   function 
   (parent, word) {
 $.ajax( {
 type :  
   ' 
   POST 
   ' 
   ,
 data : {word:word,rand:Math.random()},
 url : options.url,
 dataType :  
   ' 
   json 
   ' 
   ,
 timeout :  
   1000 
   ,
 success :  
   function 
   (json){handleResponse(parent, json);},
 error : handleError
 });
 };
 });
 };
})(jQuery);

 

使用方法:

 

< 
   style  
   type 
   ="text/css" 
   > 
   
.dropDiv  
   { 
   
 position 
   : 
    absolute 
   ; 
   
 z-index 
   : 
    10 
   ; 
   
 display 
   : 
    none 
   ; 
   
 cursor 
   : 
    hand 
   ; 
   
 border 
   : 
   1px solid #7F9DB9 
   ; 
   
 
   } 
   

.dropDiv .jhover  
   { 
   
 background-color 
   : 
    #D5E2FF 
   ; 
   
 
   } 
   
.dropDiv .list  
   { 
   
 float 
   : 
   left 
   ; 
   
 width 
   : 
   100% 
   ; 
   
 
   } 
   
.dropDiv .word  
   { 
   
float 
   : 
   left 
   ; 
   
 
   } 
   

.dropDiv .view  
   { 
   
float 
   : 
   right 
   ; 
   
color 
   : 
    gray 
   ; 
   
text-align 
   : 
    right 
   ; 
   
font-size 
   : 
    10pt 
   ; 
   
 
   } 
   
 
   </ 
   style 
   > 
   
 
   < 
   script  
   type 
   ="text/javascript" 
    src 
   ="../js/jquery-1.4.2.min.js" 
   ></ 
   script 
   > 
   
 
   < 
   script  
   type 
   ="text/javascript" 
    src 
   ="../js/autopoint.js" 
   ></ 
   script 
   > 
   
 
   < 
   script  
   type 
   ="text/javascript" 
   > 
   
$( 
   function 
   (){
$( 
   " 
   input 
   " 
   ).autopoint({url: 
   ' 
   http://localhost/xun/ajax.svl?method=getsearchhelp 
   ' 
   ,submit:[ 
   " 
   action1 
   " 
   ,  
   " 
   action2 
   " 
   ]});
});
 
   </ 
   script 
   > 
   
 
   </ 
   head 
   > 
   
 
   < 
   body 
   > 
   
 
   < 
   input  
   type 
   ="text" 
    id 
   ="search" 
    name 
   ="search" 
    size 
   ="50" 
    autocomplete 
   ="off" 
   > 
   
 
   < 
   br  
   /> 
   
 
   < 
   br  
   /> 
   
 
   < 
   br  
   /> 
   
 
   < 
   br  
   /> 
   
 
   < 
   br  
   /> 
   
 
   < 
   input  
   type 
   ="text" 
    size 
   ="50" 
    autocomplete 
   ="off" 
     
   /> 
   
 
   </ 
   body 
   >

 

servlet主要部分:

 

1 
   response.setContentType( 
   " 
   text/html 
   " 
   ); 
 
    2 
    response.setHeader( 
   " 
   Cache-Control 
   " 
   ,  
   " 
   no-cache 
   " 
   ); 
 
    3 
    response.setCharacterEncoding( 
   " 
   UTF-8 
   " 
   );
 
    4 
    String word  
   = 
    request.getParameter( 
   " 
   word 
   " 
   );
 
    5 
     
   if 
   (Utils.isBlank(word))  
   return 
   ;
 
    6 
    JSONObject json  
   = 
     
   new 
    JSONObject();
 
    7 
    JSONArray array  
   = 
     
   new 
    JSONArray();
 
    8 
    Map 
   < 
   String, Object 
   > 
    map1  
   = 
     
   new 
    HashMap 
   < 
   String, Object 
   > 
   ();
 
    9 
    map1.put( 
   " 
   word 
   " 
   , word  
   + 
     
   " 
   a1 
   " 
   );
 
   10 
    map1.put( 
   " 
   view 
   " 
   ,  
   10 
   );
 
   11 
    Map 
   < 
   String, Object 
   > 
    map2  
   = 
     
   new 
    HashMap 
   < 
   String, Object 
   > 
   ();
 
   12 
    map2.put( 
   " 
   word 
   " 
   , word  
   + 
     
   " 
   a2 
   " 
   );
 
   13 
    map2.put( 
   " 
   view 
   " 
   ,  
   15 
   );
 
   14 
    Map 
   < 
   String, Object 
   > 
    map3  
   = 
     
   new 
    HashMap 
   < 
   String, Object 
   > 
   ();
 
   15 
    map3.put( 
   " 
   word 
   " 
   , word  
   + 
     
   " 
   a3 
   " 
   );
 
   16 
    map3.put( 
   " 
   view 
   " 
   ,  
   2 
   );
 
   17 
    array.add(JSONObject.fromObject(map1));
 
   18 
    array.add(JSONObject.fromObject(map2));
 
   19 
    array.add(JSONObject.fromObject(map3));
 
   20 
    json.put( 
   " 
   data 
   " 
   , array);
 
   21 
    PrintWriter out  
   = 
    response.getWriter();
 
   22 
    out.print(json.toString());
 
   23 
    out.close();



 

其中JSONObject和JSONArray类来自json-lib.jar,为了测试方便,是直接返回数据的,实际应用中可以替换为

从数据源查取数据.