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


Posted in Javascript onMarch 19, 2013

今天看群里有人发起了人人网以前一些面试题,我以前也转载过一些,恰好闲着,挑选一题来做做,练个手。

本题有以下要求
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条数据可选,这就需要更多的判断以及请求。
所以,具体实现取决于真实的业务场景。
至此,本文结束。感谢阅读,欢迎有血有肉的置评。
Javascript 相关文章推荐
判断JavaScript对象是否可用的最正确方法分析
Oct 03 Javascript
extJs 文本框后面加上说明文字+下拉列表选中值后触发事件
Nov 27 Javascript
原生js实现改变随意改变div属性style的名称和值的结果
Sep 26 Javascript
javascript闭包传参和事件的循环绑定示例探讨
Apr 17 Javascript
JavaScript中的ubound函数使用实例
Nov 04 Javascript
jquery悬浮提示框完整实例
Jan 13 Javascript
微信JS-SDK自定义分享功能实例详解【分享给朋友/分享到朋友圈】
Nov 25 Javascript
微信小程序实战之上拉(分页加载)效果(2)
Apr 17 Javascript
vue首次赋值不触发watch的解决方法
Sep 11 Javascript
原生JS实现轮播图效果
Oct 12 Javascript
微信小程序实现电子签名并导出图片
May 27 Javascript
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
javascript实现tabs选项卡切换效果(扩展版)
Mar 19 #Javascript
javascript实现tabs选项卡切换效果(自写原生js)
Mar 19 #Javascript
jquery写个checkbox——类似邮箱全选功能
Mar 19 #Javascript
借助script进行Http跨域请求:JSONP实现原理及代码
Mar 19 #Javascript
DIV+CSS+JS不间断横向滚动实现代码
Mar 19 #Javascript
下载文件个别浏览器文件名乱码解决办法
Mar 19 #Javascript
jQuery点击tr实现checkbox选中的方法
Mar 19 #Javascript
You might like
PHP的Laravel框架中使用消息队列queue及异步队列的方法
2016/03/21 PHP
php版微信js-sdk支付接口类用法示例
2016/10/12 PHP
thinkPHP+ajax实现统计页面pv浏览量的方法
2017/03/15 PHP
PHP命令空间namespace及use的用法小结
2017/11/27 PHP
PHP框架实现WebSocket在线聊天通讯系统
2019/11/21 PHP
TP5多入口设置实例讲解
2020/12/15 PHP
浅析JavaScript中的delete运算符
2013/11/30 Javascript
js实现checkbox全选、不选与反选的方法
2015/02/09 Javascript
jQuery实现的无限级下拉菜单功能示例
2016/09/12 Javascript
用vue和node写的简易购物车实现
2017/04/25 Javascript
小程序云开发教程如何使用云函数实现点赞功能
2019/05/18 Javascript
详解Vue-cli3.X使用px2rem遇到的问题
2019/08/09 Javascript
json解析大全 双引号、键值对不在一起的情况
2019/12/06 Javascript
vue-cli3 取消eslint校验代码的解决办法
2020/01/16 Javascript
jquery检测上传文件大小示例
2020/04/26 jQuery
js实现ajax的用户简单登入功能
2020/06/18 Javascript
如何手写一个简易的 Vuex
2020/10/10 Javascript
跟老齐学Python之有容乃大的list(2)
2014/09/15 Python
Python使用matplotlib简单绘图示例
2018/02/01 Python
python3实现磁盘空间监控
2018/06/21 Python
Python中一般处理中文的几种方法
2019/03/06 Python
python数据预处理之数据标准化的几种处理方式
2019/07/17 Python
如何在python中执行另一个py文件
2020/04/30 Python
SkinCeuticals官网:美国药妆品牌
2018/04/19 全球购物
广州地球村科技数据库题目
2016/04/25 面试题
Java软件工程师综合面试题笔试题
2013/09/08 面试题
商场消防演习方案
2014/02/12 职场文书
可口可乐广告词
2014/03/20 职场文书
环保建议书500字
2014/05/14 职场文书
演讲比赛策划方案
2014/06/11 职场文书
我们的节日中秋活动方案
2014/08/19 职场文书
教师竞聘上岗演讲稿
2014/09/03 职场文书
结婚幸福感言
2015/08/01 职场文书
Spring Data JPA使用JPQL与原生SQL进行查询的操作
2021/06/15 Java/Android
python playwrigh框架入门安装使用
2022/07/23 Python
Vue深入理解插槽slot的使用
2022/08/05 Vue.js