js实现的联想输入
以前也写过一个jQuery的这种插件,但是很多地方根本不用jQuery,这个功能也有很多其它库支持,但是为了用这个功能而加载很多js插件,这样效率明显下降了很多,而且这个东西平时也很常用,所以一决心自己写了个相对比较独立的。
完成有以下功能:
- 输入字符会把以输入字符开头的提示出来。
- 支持上下方向键选择提示选项,支持循环
- 支持绑定一个数组提示,支持ajax传递输入框值请求数据。
- 支持多个选择的dom元素一块绑定数据实现输入提示。各dom元素也可以单独绑定自己的数据实现输入提示,互不影响。
- 支持中文。
首先是js的核心部分,其各部分都有较详细的说明,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
;(function(window){/* 插件开始 */var autoComplete=function(o){ var handler=(function(){ var handler=function(e,o){ return new handler.prototype.init(e,o); };/* 为每个选择的dom都创建一个相对应的对象,这样选择多个dom时可以很方便地使用 */ handler.prototype={ e:null, o:null, timer:null, show:0, input:null, popup:null, init:function(e,o){/* 设置初始对象 */ this.e=e, this.o=o, this.input=this.e.getElementsByTagName(this.o.input)[0], this.popup=this.e.getElementsByTagName(this.o.popup)[0], this.initEvent();/* 初始化各种事件 */ }, match:function(quickExpr,value,source){/* 生成提示 */ var li = null; for(var i in source){ if( value.length>0 && quickExpr.exec(source[i])!=null ){ li = document.createElement('li'); li.innerHTML = '<a href="javascript:;">'+source[i]+'</a>'; this.popup.appendChild(li); } } if(this.popup.getElementsByTagName('a').length) this.popup.style.display='block'; else this.popup.style.display='none'; }, ajax:function(type,url,quickExpr,search){/* ajax请求远程数据 */ var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); xhr.open(type,url,true);/* 同异步在此修改 */ xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var that=this; xhr.onreadystatechange = function(){ if(xhr.readyState==4) { if(xhr.status==200) { var data = eval(xhr.responseText); that.match(quickExpr,search,data);/* 相同于成功的回调函数 */ }else{ alert("请求页面异常!");/* 请求失败 */ } } }; xhr.send(null); }, fetch:function(ajax,search,quickExpr){ var that=this; this.ajax(ajax.type,ajax.url+search,quickExpr,search); }, initEvent:function(){/* 各事件的集合 */ var that=this; this.input.onfocus = function(){ if(this.inputValue) this.value = this.inputValue; var value=this.value, quickExpr=RegExp('^'+value,'i'), self=this; var els = that.popup.getElementsByTagName('a'); if(els.length>0) that.popup.style.display = 'block'; that.timer=setInterval(function(){ if(value!=self.value){/* 判断输入内容是否改变,兼容中文 */ value=self.value; that.popup.innerHTML=''; if(value!=''){ quickExpr=RegExp('^'+value); if(that.o.source) that.match(quickExpr,value,that.o.source); else if(that.o.ajax) that.fetch(that.o.ajax,value,quickExpr); } } },200); }; this.input.onblur = function(){/* 输入框添加事件 */ if(this.value!=this.defaultValue) this.inputValue = this.value; clearInterval(that.timer); var current=-1;/* 记住当前有焦点的选项 */ var els = that.popup.getElementsByTagName('a'); var len = els.length-1; var aClick = function(){ that.input.inputValue = this.firstChild.nodeValue; that.popup.innerHTML=''; that.popup.style.display='none'; that.input.focus(); }; var aFocus = function(){ for(var i=len; i>=0; i--){ if(this.parentNode===that.popup.children[i]){ current = i; break; } } //that.input.value = this.firstChild.nodeValue; for(var k in that.o.elemCSS.focus){ this.style[k] = that.o.elemCSS.focus[k]; } }; var aBlur= function(){ for(var k in that.o.elemCSS.blur) this.style[k] = that.o.elemCSS.blur[k]; }; var aKeydown = function(event){ event = event || window.event;/* 兼容IE */ if(current === len && event.keyCode===9){/* tab键时popup隐藏 */ that.popup.style.display = 'none'; }else if(event.keyCode==40){/* 处理上下方向键事件方便选择提示的选项 */ current++; if(current<-1) current=len; if(current>len){ current=-1; that.input.focus(); }else{ that.popup.getElementsByTagName('a')[current].focus(); } }else if(event.keyCode==38){ current--; if(current==-1){ that.input.focus(); }else if(current<-1){ current = len; that.popup.getElementsByTagName('a')[current].focus(); }else{ that.popup.getElementsByTagName('a')[current].focus(); } } }; for(var i=0; i<els.length; i++){/* 为每个选项添加事件 */ els[i].onclick = aClick; els[i].onfocus = aFocus; els[i].onblur = aBlur; els[i].onkeydown = aKeydown; } }; this.input.onkeydown = function(event){ event = event || window.event;/* 兼容IE */ var els = that.popup.getElementsByTagName('a'); if(event.keyCode==40){ if(els[0]) els[0].focus(); }else if(event.keyCode==38){ if(els[els.length-1]) els[els.length-1].focus(); }else if(event.keyCode==9){ if(event.shiftKey==true) that.popup.style.display = 'none'; } }; this.e.onmouseover = function(){ that.show=1; }; this.e.onmouseout = function(){ that.show=0; }; addEvent.call(document,'click',function(){ if(that.show==0){ that.popup.style.display='none'; } });/* 处理提示框dom元素不支持onblur的情况 */ } }; handler.prototype.init.prototype=handler.prototype;/* JQuery style,这样我们在处的时候就不用每个dom元素都用new来创建对象了 */ return handler;/* 把内部的处理函数传到外部 */ })(); if(this.length){/* 处理选择多个dom元素 */ for(var a=this.length-1; a>=0; a--){/* 调用方法为每个选择的dom生成一个处理对象,使它们不互相影响 */ handler(this[a],o); } }else{/* 处理选择一个dom元素 */ handler(this,o); } return this;};return window.autoComplete = autoComplete;/* 暴露方法给全局对象 *//* 插件结束 */})(window); |
其中了一些全局的自定义函数,如addEvent和在例子中将要用到的getElementsByClassName函数如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
var getElementsByClassName = function (searchClass, node, tag) {/* 兼容各浏览器的选择class的方法;(写法参考了博客园:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1529640.html,想了解更多请看这个地址) */ node = node || document, tag = tag ? tag.toUpperCase() : "*"; if(document.getElementsByClassName){/* 支持getElementsByClassName的浏览器 */ var temp = node.getElementsByClassName(searchClass); if(tag=="*"){ return temp; } else { var ret = new Array(); for(var i=0; i<temp.length; i++) if(temp[i].nodeName==tag) ret.push(temp[i]); return ret; } }else{/* 不支持getElementsByClassName的浏览器 */ var classes = searchClass.split(" "), elements = (tag === "*" && node.all)? node.all : node.getElementsByTagName(tag), patterns = [], returnElements = [], current, match; var i = classes.length; while(--i >= 0) patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)")); var j = elements.length; while(--j >= 0){ current = elements[j], match = false; for(var k=0, kl=patterns.length; k<kl; k++){ match = patterns[k].test(current.className); if(!match) break; } if(match) returnElements.push(current); } return returnElements; }};var addEvent=(function(){/* 用此函数添加事件防止事件覆盖 */ if(document.addEventListener){ return function(type, fn){ this.addEventListener(type, fn, false); }; }else if(document.attachEvent){ return function(type,fn){ this.attachEvent('on'+type, function () { return fn.call(this, window.event);/* 兼容IE */ }); }; }})(); |
原文地址: http://www.cnblogs.com/jaiho/archive/2011/02/28/js_autocomplete.html
如果忘记,在自己的语言精髓文件夹里
js实现的联想输入的更多相关文章
- JS实现联想输入(二)
JS实现联想输入(一)是主要针对单列结构的JSON格式的数据的,如果想满足多列结构的JSON格式的数据,也是非常容易的,其解决方案有至少有三种选择: 1:在后台Action方法中将多列的值拼成单列结构 ...
- JS实现联想输入(一)
这里是我们的项目中的一个使用JS实现联想输入的功能代码,在此做个小的记录并且将它分享给大家希望对园中的朋友有用! 我将分享三段都非常简单的代码,仅仅作为个人的一点小小的积累而已! 1:后台的Actio ...
- autocomplete实现联想输入,自动补全
jQuery.AutoComplete是一个基于jQuery的自动补全插件.借助于jQuery优秀的跨浏览器特性,可以兼容Chrome/IE/Firefox/Opera/Safari等多种浏览器. 特 ...
- bigautocomplete实现联想输入,自动补全
bigautocomplete是一款Jquery插件.用它实现仿搜索引擎文本框自动补全插件功能很实用,使用也很简单,引入了插件之后写几行代码就可以实现,可以灵活设置. 先看效果图: 上图是通过ajax ...
- javascript 实现类似百度联想输入,自动补全功能
js 实现类似百度联想输入,自动补全功能 方案一: search是搜索框id="search" //点击页面隐藏自动补全提示框 document.onclick = functi ...
- Vue.js 和 MVVM 小细节
MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自 ...
- js学习笔记:操作iframe
iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- JS调用Android、Ios原生控件
在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...
随机推荐
- gitbook生成的_book文件本地打开后链接失效问题
Gitbook 生成本地 html 的问题 在本地用 gitbook-cli根据 Summary 生成目录 然后在每个 md 文件里书写内容 然后用 gitbook serve .生成本地 html ...
- direct.h头文件(对目录操作)
chdir()改变当前目录的函数原形:int chdir(const char *path)功能:把由path指定的目录改为当前目录.path参数中可以指定驱动器号,如“a:\\ddd”, 但只是改变 ...
- Top K 算法详解
http://xingyunbaijunwei.blog.163.com/blog/static/7653806720111149318357/ 问题描述 百度面试题: ...
- C#排序相关算法
http://www.cnblogs.com/zxjyuan/archive/2010/01/06/1640092.html 冒泡法: Using directivesnamespace Bubble ...
- WEBSTORM中html文件运行之后出现乱码的问题解决
出现如下问题: 解决方案: 1.点击"文件编码" 2.选择GBK 3.点击Reload. 4.此时,源代码中的中文字体会变成乱码,把这些乱码重新输入成原先的中文.然后运行html文 ...
- Struts1之编码问题
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding=& ...
- javascript中window.location.search方法简介
window.location.search方法是截取当前url中"?"后面的字符串,示例如下: 例如:http://www.firefoxchina.cn/?ntab截取后的字符 ...
- [NOIP2018 TG D1T3]赛道修建
题目大意:$NOIP2018\;TG\;D1T3$ 题解:题目要求最短的赛道的长度最大,可以想达到二分答案,接着就是一个显然的树形$DP$. 发现对于一个点,它子树中若有两条链接起来比要求的答案大,一 ...
- Eclipse中的引用项目报Could not find *.apk!解决办法
百度上很多关于Could not find *.apk!这种编译报错的解决帖子,但是笔主在这里主要说一下在 引用工程项目的场景 下报这个错误消息的问题(不影响本项目的正常编译运行!). 笔主刚从谷歌上 ...
- ubuntu下使用sudo 出现unable to resolve host 解决方法
Linux 环境, 假设这台机器名字叫dev(机器的hostname), 每次执行sudo 就出现这个警告讯息:sudo: unable to resolve host dev虽然sudo 还是可以正 ...