当前位置: 代码迷 >> Web前端 >> input输入上列提示
  详细解决方案

input输入上列提示

热度:328   发布时间:2012-10-17 10:25:47.0
input输入下列提示

今天在项目中遇到一个需求,就是在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));
}

?

  相关解决方案