input输入框的自动匹配(原生代码)

所属分类: 网络编程 / JavaScript 阅读数: 700
收藏 0 赞 0 分享
今天看群里有人发起了人人网以前一些面试题,我以前也转载过一些,恰好闲着,挑选一题来做做,练个手。

本题有以下要求
1. 使用原生代码实现,不可使用任何框架;
2. 对 input框中输入的字符进行匹配,将匹配到的内容以菜单的形式展现在 input框的下方;
3. 只针对英文字符进行匹配,并且匹配到的内容在菜单中加粗;
4. 通过键盘上的上下箭头可以对菜单进行选择,按下回车后将选中的内容写入到 input框中;
思 路
捕捉输入变化,用用户输入的值(下称输入值)去匹配列表项,这里假设列表项是查询返回的一个数组(下称列表),匹配方式为用输入值作为开始值匹配每个列表值,将符合筛选条件的项输出到页面。
分 析
第三点要求中关键字是加粗,这里用正则替换就好了。
第四点要求的关键字就比较多了,一句话暗藏许多杀机,这一部分主要是针对键盘,首先是上下按键,然后是回车,还有一个写入到input框。

到这,如果你认为完了那就操之过急了,至少还有4个隐性的需求。
•第一项默认高亮显示,上下按键的同时当前项高亮。
•按下Enter默认第一项被选中。
•鼠标经过时当前项高亮。
•支持点击选中项。
也许还有所遗漏,这里就不纠结了。
实 践
这虽然是一道JS题,但这之前,页面结构还是要先写好。
复制代码 代码如下:

<div id="wrap">
<input type="text" id="put" />
</div>
<div id="menu">
<div>
<ul id="output">
<li>占位</li>
<li>占坑</li>
</ul>
</div>
</div>

由于不允许用框架,这里对一些可能要到的方法作一个简单的封装。
首先创建一个封装对象,暂且取名 dom,接下来的原生方法都放进这个对象以作复用。
复制代码 代码如下:

var dom = {
$ : function( id ){
return document.getElementById(id);
},
tag : function( tagName,root ){
root = root ? root : document;
return this.makeArray( root.getElementsByTagName(tagName) );
},
bind : function( element,type,handler ){
if( document.addEventListener ){
element.addEventListener( type,handler,false );
}else if( document.attachEvent ){
element.attachEvent( 'on' + type,handler );
};
},
removeClass : function( list,name ){
var el = list[i],
r = new RegExp('\\s*\\b' + name + '\\b\\s*','g');
for( var i = 0 , len = list.length ; i < len ; i++ ){
var cur = list[i];
if( r.test( cur.className ) ){
cur.className = cur.className.replace(r,'');
};
};
},
height : function( element ){
return element.offsetHeight;
},
getBound : function( element ){
return element.getBoundingClientRect();
},
getText : function( element ){
return element.textContent ? element.textContent : element.innerText;
},
trim : function( string ){
return string.replace( /^\s*(.*)\s*$/,'$1' );
},
makeArray : function( tagList ){
for( var i = 0 , arr = [] , len = tagList.length ; i < len ; i++ ){
arr.push( tagList[i] );
};
return arr;
},
isVisible : function( element ){
return element.style.display == 'block';
}
};

接着再创建一个对象,用于存放具体的处理逻辑,作者英文比较狗血,就叫autoMatch吧。
这个对象要做的事情可多了:
•确定好菜单的位置;
•实时处理用户输入;
•处理鼠标和键盘按键动作;
确定菜单的位置 用封装对象dom的getBound方法,返回一个边界对象,此对象有两个属性left和top。眼熟吧,它类似jQuery里的offset()方法。
处理用户输入这里值得一提,由于是实时处理,开始考虑用onchange事件,但是它只会在失去焦点时才触发,所以是不合理的。
这时我的目光转向了oninput,它完全能够胜任工作。
复制代码 代码如下:

dom.bind( obj.input,'input' , this.inputProcess );

可是,IE又做了一回不走寻常路的事儿。它并不支持oninput。
空欢喜一场,白瞎了!
凡事总是有转机的。角落里的onpropertychange向我们缓缓走来…,它和oninput非常相似,有着一样的特性,至少在捕捉input输入方面,正是我想要的,对付IE,我们都用它,用了都说好。
再绑定一次:
复制代码 代码如下:

dom.bind( obj.input,'propertychange' , this.inputProcess );

接下来是按键,上,下,回车。对应的键编码分别是38、40、13,唯一需要注意的是FF和IE的属性名称不一样。
详细的实现细节见Demo:
猛击我查看Demo
真实业务场景中,可能要对用户的输入作实时Ajax查询,这代表着每敲一个字母都会有一次查询。
然而如此频繁发送Ajax请求实在太不划算,响应速度上也不容许这样的实现。
我的思路是当用户敲第一个字母时,发送一次请求(请求数据一般有数量限制,一般是10条),并将返回值储存起来(下称缓存)。
在第一个字母之后的用户输入,都在缓存里面筛选,到这里就如同本地查询一样了,每输入一个字母,精确度越来越高,缓存越来越小。
当用户清空,重新输入时重复以上的步骤。
当然,不排除会有一些更加复杂的业务场景,比如,在匹配充足的情况下,要保证用户每次输入都有10条数据可选,这就需要更多的判断以及请求。
所以,具体实现取决于真实的业务场景。
至此,本文结束。感谢阅读,欢迎有血有肉的置评。
更多精彩内容其他人还在看

jQuery LigerUI 使用教程表格篇(1)

ligerGrid是ligerui系列插件的核心控件,用户可以快速地创建一个美观,而且功能强大的表格,支持排序、分页、多表头、固定列等等
收藏 0 赞 0 分享

JavaScript中常用的运算符小结

JavaScript中常用的运算符小结,需要的朋友可以参考下。
收藏 0 赞 0 分享

深入理解JavaScript系列(13) This? Yes,this!

在这篇文章里,我们将讨论跟执行上下文直接相关的更多细节。讨论的主题就是this关键字。实践证明,这个主题很难,在不同执行上下文中this的确定经常会发生问题
收藏 0 赞 0 分享

javascript (用setTimeout而非setInterval)

javascript (用setTimeout而非setInterval)如果用setInterval 可能出现 下次调用会在前一次调用前调用
收藏 0 赞 0 分享

JavaScript中两个感叹号的作用说明

用两个感叹号的作用就在于,如果明确设置了o中flag的值(非null/undefined/0""/等值),自然test就会取跟o.flag一样的值;如果没有设置,test就会默认为false,而不是null或undefined
收藏 0 赞 0 分享

javascript写的简单的计算器,内容很多,方法实用,推荐

最近用javascript写了一个简单的计算器,自己测试感觉还好,代码都给了注释,非常不错,推荐大家学习。
收藏 0 赞 0 分享

js的表单操作 简单计算器

javascript写的简单的加减乘除计算器,里面涉及到一些方法还是很实用的哦,新手不要错过
收藏 0 赞 0 分享

Jquery中删除元素的实现代码

empty用来删除指定元素的子元素,remove用来删除元素,或者设定细化条件执行删除
收藏 0 赞 0 分享

javaScript 利用闭包模拟对象的私有属性

JavaScript缺少块级作用域,没有private修饰符,但它具有函数作用域。作用域的好处是内部函数可以访问它们的外部函数的参数和变量(除了this和argument
收藏 0 赞 0 分享

为JavaScript类型增加方法的实现代码(增加功能)

大家在js开发过程中有些功能已经满足不了我们的需求,或没有我们需要的功能,那么我们就可以自己扩展下,个性化js
收藏 0 赞 0 分享
查看更多