实现google那种输入框提示的功能(转载)

本文介绍如何在网页输入框中实现自动补全功能,包括前端布局、使用Ajax获取数据、显示下拉菜单及键盘导航等细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://www.cnblogs.com/woodfish1988/archive/2008/10/18/1314221.html

 

 

今天在项目中遇到一个需求,就是在input输入框中录入数据时(名字),如果敲入了一部分,在数据库中存在已有的姓名的前缀与之匹配,就弹出一个 google页面那种效果的下拉框,把相关的姓名列出来供他选择。可以用箭头上下选择,也可以用鼠标选择。这样可以提高录入的效率。

    输入框的布局如下:

   

  最终的效果如下:

 

 

  表单中输入框的html代码为:

< tr >< td > 发件人 </ td >< td >< input  type ="text"  name ="sendername"  id ="sendername"  value ="" /></ td ></ tr >

 

为了在输入一些内容时,能够显示出那个选择框,我们要建立一个div,初始时不可见,当需要时就显示出来,并且将它移动到正确的位置。这个div采用的定位为绝对定位,这样就可以在整个页面用left和top来定位了,z-index为99,这样就可以盖住下面的东西。选择框的div为:

< div  id ="helper"  class ="gac_m"  style ="visibility:hidden;"  width ="100%" >
</ div >

 gac_m的css定义为:

.gac_m  {
background
: white none repeat scroll 0 0 ;
border
: 1px solid black ;
cursor
: default ;
font-size
: 13px ;
line-height
: 17px ;
margin
: 0 ;
position
: absolute ;
z-index
: 99 ;
width
: 100px ;
left
: 10px ;
top
: 10px ;
}

 当需要显示时,我们需要将id为helper的div移动到正确的位置,这个位置就是input输入框的正下方,left即为input的相对页面左边的位移,top即为input相对页面上边的位移加上input本身的高度。现在的问题是怎么取得一个元素的相对页面的绝对位置,这个可以通过offsetParent取的父亲结点递归的来算。下面函数getAbsPosition用来取得元素obj的绝对位置,gettable(obj)用来把id为helper的div定位到obj正下方:

function  getAbsPosition(obj) {
    
var  r  =  {
        left: obj.offsetLeft,
        top : obj.offsetTop
    };
    r.left 
=  obj.offsetLeft;
    r.top  
=  obj.offsetTop;
    
if (obj.offsetParent) {
        
var  tmp  =  getAbsPosition(obj.offsetParent);
        r.left 
+=  tmp.left;
        r.top  
+=  tmp.top;
    }
    
return  r;
  }
  
function  gettable(obj) {
    
var  pos  =  getAbsPosition(obj);
    pos.top 
+=  obj.offsetHeight;
    document.getElementById(
' helper ' ).style.top  =  pos.top  +   " px " ;
    document.getElementById(
' helper ' ).style.left  =  pos.left  +   " px " ;
    document.getElementById(
' helper ' ).style.width  =  obj.offsetWidth  +   " px " ;
    document.getElementById(
' helper ' ).style.visibility  =   '' ;
  }

现在可以定位并且显示id为helper的div了,下面的问题是当输入框中的内容改变时,采用Ajax去服务器取得数据,然后更新div中的内容,并且显示出来。那么怎么侦测输入框中的内容改变了呢?如果采用onchange事件,只有当输入框失去焦点时才会触发,所以我们只有采用定时器的方式了,每隔一个时间片检查一下输入框的值,如果值改变了,就执行更新过程。下面checkvalue函数就是用来给定时器的函数,用来检查输入框的内容是否改变,getNameResponse是Ajax的回调函数,用来对服务器传回的JSON数据解码并且以一定的方式显示在div中。

function  checkvalue() {
    
var  nowvalue  =  document.getElementById( ' sendername ' ).value;
    
if (prevalue  !=  nowvalue) {
        Ajax.call(
' useradv.php?act=getsendername&name= ' + nowvalue, '' ,getNameResponse,  ' GET ' ' JSON ' );
    }
    prevalue 
=  nowvalue;
    setTimeout(checkvalue,
100 );
  }
  
function  getNameResponse(result) {
    
var  info  =  result.content;
    
var  html  =   ' <table width="100%"> ' ;
    
for ( var  i  =   0 ;i  <  info.length; i ++ ) {
        html 
+=   ' <tr id="tr '   +  (i + 1 + ' " onmouseover="choosetr( '   +  (i + 1 + ' );" onclick="selecttr();"> '
              
+   ' <td colspan="2"> '   +  info[i].sendername  +   ' </td></tr> ' ;
    }
    html 
+=   ' <td align="left"><font color="red">按空格键选择</font></td> '
           
+ ' <td align="right"><a href="#" onclick="document.getElementById(/ ' helper/ ' ).style.visibility=/ ' hidden/ ' ;"> ' +
          
' 关闭</a></td></tr></table> ' ;
    
    document.getElementById(
' helper ' ).innerHTML  =  html;
    
if (info.length  >   0 ) {
        gettable(document.getElementById(
' sendername ' ));
    }
else {
        document.getElementById(
' helper ' ).style.visibility  = ' hidden ' ;
    }
  }

 其中tr的className为gca_b表示该行被选中,其CSS定义为:

.gac_b  {
background
: #3366CC !important ;
color
: white ;
}

 

下面需要解决的问题是用向上和向下的按键来在选择框中选择,这样就需要检测键盘按键了,可以直接通过document.onkeydown来注册按键检测函数,当按下向上和向下的键时,就上下移动选中的行,函数choosetr(nextid)用来选择第nextid行,当然需要记录nowid为前面选中的行,然后selecttr()是当按了空格键或者用鼠标点击了后模拟选中的动作,用选中的值来填充input。

var  nowid  =   0 ;
function  selecttr() {
    
try
    {
        
if (document.getElementById( ' helper ' ).style.visibility  ==   ' hidden ' return ;
        document.getElementById(
' sendername ' ).value  =  
document.getElementById(
' tr ' + nowid).cells[ 0 ].innerHTML;
        setTimeout(
function (){

                        document.getElementById('sendername').value

                        =Utils.trim(document.getElementById('sendername').value);},50);      

        falg = false;

        nowid  =   0 ;
        
var  eles  =  document.getElementsByName( ' trname ' );
        
for ( var  i  =   0 ; i  <  eles.length; i ++ ) {
            eles[i].className 
=   '' ;
        }
        document.getElementById(
' helper ' ).style.visibility  = ' hidden ' ;
    }
    
catch  (e)
    {
    }
  }
document.onkeydown 
=   function (e) {
    
var  keycode;
    
try
    {
        keycode 
=  event.keyCode;
    }
    
catch  (err)
    {
        keycode 
=  e.keyCode;
    }
    
if (keycode  ==   40 ) {
        
// 按了向下的键
        choosetr(nowid + 1 );
    } 
else   if (keycode  ==   38 ) {
        
// 按了向上的键
        choosetr(nowid - 1 );
    } 
else   if (keycode  ==   32 ) {
        selecttr();
    }
  }
  
function  choosetr(nextid) {
     
var  len  =   0 ;
     
do
     {
        
try
        {
            
var  obj  =  document.getElementById( ' tr ' + (len + 1 ));
            
if (obj) len ++ else   break ;
        }
        
catch  (e)
        {
            
break ;
        }
     }
while ( 1 );
     
if (nextid  >  len) nextid  =   1 ;
     
if (nextid  <   1 ) nextid  =  len;
     
if (nowid  >= 1   &&  nowid  <=  len) {
         document.getElementById(
' tr '   +  nowid).className  =   '' ;
     }
     document.getElementById(
' tr '   +  nextid).className  =   ' gac_b ' ;
     nowid 
=  nextid;
  }
  setTimeout(checkvalue,
100 );

 这样就可以了,最后需要注意的是有个小问题:浏览器自带的自动历史选择下拉框会与我们做的冲突,解决方法就是设置input的oncomplete="off"。

最后贴一下服务器端的php程序:


elseif  ( $action   ==   ' getsendername ' ) {
    
$name   =   trim ( $_GET [ ' name ' ]);
    
$rows   =   array ();
    
if ( strlen ( $name >   0 ) {
        
$sql   =   " select distinct sendername from  " . $GLOBALS [ ' ecs ' ] -> table( ' useradv ' ) .
               
"  where sendername like ' $name %' and sendername != ' $name ' limit 0,10 " ;
        
$rows   =   $GLOBALS [ ' db ' ] -> getAll( $sql );
    }
    
include_once (ROOT_PATH  .   ' includes/cls_json.php ' );
    
$json   =   new  JSON();
    
$result   =   array ( ' error ' => 0 ,   ' message ' => '' ,   ' content ' => '' );
    
$result [ ' content ' =   $rows ;
    
die ( $json -> encode( $result ));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值