jQuery Autocomplete自动完成插件


Posted in Javascript onJuly 17, 2010

相对于同类插件,他的特色有3点。
1、可缓存查询结果 (二次查询速度快)
2、非keyup监听方式 (解决某些系统/情况下无法触发keyxxx事件的问题)
3、简洁的参数 (好看?)

插件性能尚好,我的E6500、2G内存,30秒内一共发生了4469次调用,耗时94.65毫秒;百度的是2432次调用,80.24毫秒。

接近1倍的调用是jQuery中的问题,但具体原因我还没弄明白,如果那位兄弟知道的还请不吝赐教。

调用方法

jQuery("#kw").suggest({ 
url:siteConfig.suggestionUrl, 
params:{ 
kw:function(){return jQuery("#kw").val()}, 
n:10 
} 
});

参数url:baseUrl,例如http://www.target.com/search.php
参数params:url的后缀列表,范例中拼合的url为:http://www.target.com/search.php?kw=xxx&n=10&callback=?(默认加入callback)
参数delay:输入间隔时间,主要是为了降低负载,数值越大,负载越低,查询速度越慢。
参数cache:是否实用缓存,默认为true,例如当搜索“test”时,程序会将对应的查询结果缓存,当第二次搜索test时直接从缓存中读取。
参数formId:必须填写,form表单的id
参数callback:是否使用jsonp以便处理跨域问题。
核心代码:
suggest.js
(function($){ 
$.tools = $.tools || {version: '1.0'}; 
$.tools.suggest = {}; 
$.tools.suggest.defaults = { 
url : null, 
params : null, 
delay : 100, 
cache : true, 
formId : '#search_form', 
focus:null, 
callback : true 
} 
$.tools.suggest.borderKey = { 
UP: 38, 
DOWN: 40, 
TAB: 9, 
ESC: 27, 
ENTER:13 
} $.fn.suggest=function(options,fn){ 
var options,key = $.tools.suggest.borderKey; 
if($.isFunction(options)){ 
fn=options; 
options = $.extend({}, $.tools.suggest.defaults, key); 
}else{ 
options = $.extend({}, $.tools.suggest.defaults, key, options); 
} 
return this.each(function(){ 
var 
self = $(this), 
url = options.url, 
params = options.params, 
searchUrl = null, 
searchtimer = 0, 
delay = options.delay, 
cache = options.cache, 
callback = options.callback, 
formobj = $(options.formId), 
focus = options.focus, 
rebox = $('<ul/>').attr("id","suggest"), 
htmlLi = null, 
litop = null, 
lileft = null, 
liwth = null, 
tip = false, 
val = null, 
rlen = null, 
UP = options.UP, 
DOWN = options.DOWN, 
TAB = options.TAB, 
ESC = options.ESC, 
ENTER = options.ENTER, 
index = -1, 
choseKey = null, 
backval = null, 
hidden = false, 
locksuggest = false 

//init 
if(focus){ 
self.focus(); 
searchtimer = setInterval(getKey, delay); 
} 
self.bind("focus",function(){ 
searchtimer = setInterval(getKey, delay); 
// 触发焦点时初始化backval的值 
backval = (backval=$.trim(self.val()))==''?null:backval; 
}) 
.bind("blur",function(){ 
clearInterval(searchtimer); 
searchtimer = 0; 
hideResult(); 
}) 
.bind("keydown",function(e){ 
// 少于10项不使用switch 
if(e.keyCode == UP){ 
clearInterval(searchtimer); 
searchtimer = 0; 
if($('#suggest').css('display') == 'none'){ 
reSet(); 
return false; 
} 
index--; 
if(index<0){ 
index=Math.abs(rlen)-1; 
} 
changeSelect(index); 
e.preventDefault(); 
return false; 
}else if(e.keyCode == DOWN){ 
clearInterval(searchtimer); 
searchtimer = 0; 
if($('#suggest').css('display') == 'none'){ 
reSet(); 
return false; 
} 
index++; 
if(index>=rlen){ 
index=0; 
} 
changeSelect(index); 
e.preventDefault(); 
return false; 
}else if(e.keyCode == TAB){ 
clearInterval(searchtimer); 
searchtimer = 0; 
hideResult(); 
}else if(e.keyCode == ESC){ 
clearInterval(searchtimer); 
searchtimer = 0; 
hideResult(); 
return false; 
}else if(e.keyCode == ENTER){ 
clearInterval(searchtimer); 
searchtimer = 0; 
}else if(searchtimer == 0){ 
searchtimer = setInterval(getKey, delay); 
} 
}); 
// 获取关键词 
function getKey(){ 
val = $.trim(self.val()); 
// 关键词不为空且关键词不重复 
if(!!val && val!=backval){ 
backval = val; 
// 如不需要缓存结果,设cache为false 
if(cache && !!$.tools.suggest[val]){ 
index = -1; 
rlen = $.tools.suggest[val][1]; 
appendSuggest($.tools.suggest[val][0]); 
}else{ 
searchurl = url+'?'+$.param(params); 
getResult(searchurl,function(htmltemp,htmllen){ 
index = -1; 
rlen = htmllen; 
appendSuggest(htmltemp); 
}); 
} 
} 
// 关键词为空 
if(!!!val && !hidden){ 
hideResult(); 
} 
} 
// 获取提示数据 
function getResult(searchurl,fn){ 
if(callback){searchurl = searchurl+'&callback=?';} 
$.getJSON(searchurl,function(data){ 
var htmltemp = '', 
htmllen = 0, 
inputWord = self.val() 
$.each(data.list,function(i,n){ 
if(n.word != inputWord){ 
htmltemp += '<li>'+n.word+'</li>'; 
htmllen++; 
} 
}); 
if(cache && !!!$.tools.suggest[val]){$.tools.suggest[val]=[htmltemp,htmllen];} 
fn.call(document,htmltemp,htmllen) 
}); 
} 
// 插入提示数据 
function appendSuggest(result){ 
locksuggest = hidden = false; 
if(!!result){ 
if(!tip){ 
litop = self.offset().top+self.outerHeight()-1; 
lileft = self.offset().left; 
liwth = self.outerWidth()-2; 
rebox.css({'position':'absolute','top':litop,'left':lileft,'width':liwth}).html(result).appendTo('body').show(); 
tip = true; 
}else{ 
rebox.html(result).show(); 
} 
rebox.find('li').bind('mouseover',function(){ 
// 锁定提示层,保证不因冒泡关闭提示层 
locksuggest = true; 
index = $(this).index(); 
changeSelect(index,false); 
}) 
.bind('click',function(){ 
changeSelect(index); 
searchSubmit(); 
}); 
rebox.bind('mouseout',function(){ 
locksuggest = false; 
}) 
}else{ 
// 如果检索结果为空,清空提示层 
rebox.hide(); 
} 
} 
function changeSelect(index,v){ 
v=v==false?false:true; 
var obj = rebox.find('li').eq(index); 
rebox.find('li.mo').removeClass('mo'); 
obj.addClass("mo"); 
if(v){ 
choseKey = backval = obj.html(); 
self.val(choseKey); 
} 
} 
function reSet(){ 
if(!!self.val()){ 
index = -1; 
$('#suggest').css('display','block'); 
rebox.find('li.mo').removeClass('mo'); 
// 根据html结构重新计算提示结果长度 
rlen = rebox.find('li').size(); 
} 
} 
function hideResult(){ 
if(!locksuggest){ 
choseKey = backval = null; 
hidden = true; 
rebox.hide(); 
} 
} 
function searchSubmit(){ 
self.val(choseKey); 
hideResult(); 
clearInterval(searchtimer); 
formobj.submit(); 
} 
}); 
} 
})(jQuery);

代码打包下载
Javascript 相关文章推荐
JavaScript的setAttribute兼容性问题解决方法
Nov 11 Javascript
js调试系列 源码定位与调试[基础篇]
Jun 18 Javascript
浅谈js的setInterval事件
Dec 05 Javascript
node.js中的http.request.end方法使用说明
Dec 10 Javascript
node.js中的http.response.write方法使用说明
Dec 14 Javascript
JQuery实现简单的服务器轮询效果实例
Mar 31 Javascript
js 获取当前web应用的上下文路径实现方法
Aug 19 Javascript
ExtJs的Ext.Ajax.request实现waitMsg等待提示效果
Jun 14 Javascript
JavaScript实现简单的树形菜单效果
Jun 23 Javascript
原生js实现简单的焦点图效果实例
Dec 14 Javascript
layui操作列按钮个数和文字颜色的判断实例
Sep 11 Javascript
浅谈Vue使用Cascader级联选择器数据回显中的坑
Oct 31 Javascript
一个js拖拽的效果类和dom-drag.js浅析
Jul 17 #Javascript
JavaScript 浏览器验证代码(来自discuz)
Jul 17 #Javascript
IE6,IE7下js动态加载图片不显示错误
Jul 17 #Javascript
js模拟类继承小例子
Jul 17 #Javascript
javascript 循环读取JSON数据的代码
Jul 17 #Javascript
一个可绑定数据源的jQuery数据表格插件
Jul 17 #Javascript
js跨域问题之跨域iframe自适应大小实现代码
Jul 17 #Javascript
You might like
syphon 虹吸式咖啡冲泡冲煮倒水的得与失
2021/03/03 冲泡冲煮
php一个找二层目录的小东东
2012/08/02 PHP
php在window iis的莫名问题的测试方法
2013/05/14 PHP
完美实现wordpress禁止文章修订和自动保存的方法
2014/11/03 PHP
PHP获取昨天、今天及明天日期的方法
2016/02/03 PHP
php+redis在实际项目中HTTP 500: Internal Server Error故障排除
2017/02/05 PHP
PDO::query讲解
2019/01/29 PHP
利用jQuery接受和处理xml数据的代码(.net)
2011/03/28 Javascript
javaScript矢量图表库-gRaphael几行代码实现精美的条形图/饼图/点图/曲线图
2013/01/09 Javascript
javascript限制文本框只允许输入数字(曾经与现在的方法对比)
2013/01/18 Javascript
百度判断手机终端并自动跳转js代码及使用实例
2014/06/11 Javascript
使用jQuery.wechat构建微信WEB应用
2014/10/09 Javascript
jQuery1.9+中删除了live以后的替代方法
2016/06/17 Javascript
JavaScript中闭包之浅析解读(必看篇)
2016/08/25 Javascript
vue省市区三联动下拉选择组件的实现
2017/04/28 Javascript
JavaScript实现QQ列表展开收缩扩展功能
2017/10/30 Javascript
vue2.0模拟锚点的实例
2018/03/14 Javascript
详解Next.js页面渲染的优化方案
2019/01/27 Javascript
node中使用es6/7/8(支持性与性能)
2019/03/28 Javascript
jstree中的checkbox默认选中和隐藏示例代码
2019/12/29 Javascript
Vue vm.$attrs使用场景详解
2020/03/08 Javascript
记一次react前端项目打包优化的方法
2020/03/30 Javascript
vue数据更新UI不刷新显示的解决办法
2020/08/06 Javascript
[29:16]完美世界DOTA2联赛决赛日 Inki vs LBZS 第三场 11.08
2020/11/10 DOTA
Python自动化部署工具Fabric的简单上手指南
2016/04/19 Python
tensorflow构建BP神经网络的方法
2018/03/12 Python
python 从csv读数据到mysql的实例
2018/06/21 Python
Python如何设置指定窗口为前台活动窗口
2020/08/12 Python
盛大笔试题
2016/11/05 面试题
Java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
2012/05/30 面试题
迅雷Cued工作心得体会
2014/01/27 职场文书
党员评议自我评价
2015/03/03 职场文书
《所见》教学反思
2016/02/23 职场文书
简历自我评价范文
2019/04/24 职场文书
详解Python小数据池和代码块缓存机制
2021/04/07 Python
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
2022/04/19 Java/Android