一、需求

  我们经常会遇到【站内搜索】的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示。例如:某公司人事管理系统,想搜索李XX,只要输入“李”,系统自然会提示一些姓李的员工,这样方便用户使用。说白了,就是用户边输入,系统会提示相关的结果;或者,当用户点击搜索框时,就推荐一些内容,如360、百度都会提示今天的主要新闻或搜索量大的内容。

  jquery 已经有一个这样的插件了,叫 autocomplete, 但我觉得不好用。关于autocomplete的介绍也很多,有兴趣的朋友可以去试试。

  看标题就知道,这里只是分享一个插件,不会讨论后台搜索的相关算法和过程,也就是说,后台返回特定格式的数据,控件负责渲染结果呈现。ok,先看一下效果图:

  效果一:

  

  效果图二:

  

  样式与控件无关,只需要一个 input text 就可以了。

二、参数说明

  控件以json格式作为传输格式。参数比较多,大部分都有默认值(具体看源码),有些可能不常用,保持默认即可。如下:

  url: 请求地址。如:Handler.ashx, 后台获取数据的地址

property: 要显示的json对象的属性。如果我们直接返回["tom","tom cat","tom2"] 这样的形式,那么该属性可以不用设置;但有时候我们会返回[{"Name":"tom","ID":"001"},{"Name":"tom cat","ID":"002"},{"Name":"tom2","ID":"003"}] 这样的形式,显示的是Name,那么设置该属性为"Name"即可。至于我们想在点击的时候获得点击的项的ID,通过点击事件即可。

itemNumber: 显示的项数目。

isEmptyRequest: focus时,空白是否发起请求。就像前面说的,如果点击搜索框时(此时没有内容),想要推荐一些内容,设置该属性为true,即会发起请求。

defaultValue: 默认值。通常会是:“请输入关键词...” 这类的提示。

width: 下拉列表宽度。

  aligner: 要对齐的元素。

maxHeight: 最大高度。如果设置该高度,超过时就会出现滚动条。

ajax:{
        timeout: 超时时间
            cache: 是否缓存
      },

  event:{          
           setData: 发送请求前触发。用于设置参数
           itemClick: 点击项触发
           enterKeydown: 按下enter键触发
           beforeRender: 所有项呈现前触发
           endRender: 所有项呈现后触发
           itemBeforeRender: 项呈现前触发
           itemAfterRender: 项呈现后触发           
           beforeSend: 发送请求前触发。用户设置请求头部参数等,相当于jquery ajax 的 beforeSend。
     }

  event 里的方法都会在适当的时候触发,需要注意的是,所有方法都接收一个参数,该参数是一个对象,有4个属性,某些情况如果没有该属性的,则为空。包括如下属性:

   jthis: input 的 jQuery 对象。

   jItem: 项的 jQuery 对象。

data: 返回的 json 字符串。如果在前台需要对返回 json 再进行处理,那么可以通过 data 属性获得,处理完成后,需要将 json 字符串 return。

  event: 事件对象,如按下 enter 时的事件对象。

三、例子

  使用例子:

    $("#search").intellSearch({
url:"Handler.ashx",
property:"Name",
itemNumber:5,
isEmptyRequest:false,
defaultValue:"请输入关键字...",
width:$("#search").width() + 2,
maxHeight:-1,
event:{
itemClick:function(obj){
alert(obj.item.ID);
},
enterKeydown:function(obj){
if(obj.item){
alert("有当前项");
}else{
alert("没有当前项");
}
}
}
});

四、总结  

  如果你还有自己的逻辑需要处理,也支持链式调用,大可以这样写 $("#search").intellSearch({参数...}).focus(function(){你的处理...});

  分享该插件希望能帮助到有需要的朋友,主要用于学习。由于是v1.0,可能还有一些bug,有发现的朋友也可以告诉我,我会及时修正。  

附源代码

js代码

/*搜索智能提示 v1.0
date:2015.09.08
*/
;(function(w,$){
$.fn.intellSearch = function(options){
var jthis = this;
var _dftOpts = {
url:"",//请求地址或数组
property:"",//要显示的json对象的属性
itemNumber:5,//显示的条数
isEmptyRequest:false,//focus空白是否发起请求
defaultValue:"",//默认值
width:0,//列表宽度
aligner:jthis,//要对齐的元素
maxHeight:-1,//最大高度
ajax:{
timeout:3000,//超时时间
cache:true//是否缓存
},
event:{
/*参数说明:parameter:{jthis:"jq input",jItem:"jq item",data:"json result",event:"event"}*/
setData:null,//设置参数
itemClick:null,//点击项触发
enterKeydown:null,//按下enter键触发
beforeRender:null,//所有项呈现前触发
endRender:null,//所有项呈现后触发
itemBeforeRender:null,//项呈现前触发
itemAfterRender:null,//项呈现后触发
beforeSend:null//发送请求前触发
}
};
$.extend(_dftOpts,options);
if(!_dftOpts.url){
throw Error("url不能为空!");
}
var jResult;
var _value = "";
var _ajax = _dftOpts.ajax;
var _event = _dftOpts.event;
var _cache = [];
var _focusCount = 0;//防止focus触发多次(sogou) /*on window*/
window.intellObj = window.intellObj || {}; /*for global event*/
window.intellDocumentClick = window.intellDocumentClick || function(e){
if(!window.intellObj.jthis){
return;
}
if(e.target !== window.intellObj.jthis[0]){
setIntellObj(null);
}
}
window.intellDocumentKeydown = window.intellDocumentKeydown || function(e){
var jthis = window.intellObj.jthis;
if(!jthis){
return;
}
var code = e.keyCode;
var value = window.intellObj.value;
var jResult,jCurItem,keyword;
if(code === 13 || code === 38 || code === 40){
jResult = window.intellObj.jResult;
jItems = jResult.find("li");
jCurItem = jResult.find("li.cur");
if(code === 13){
if(jCurItem.length > 0){
jCurItem.click();
}else{
setIntellObj(null);
if(_event.enterKeydown){
_event.enterKeydown({"jthis":jthis,"event":e});
}
}
jthis.blur();
}else if(jItems.length > 0){
if(code === 38){
if(jCurItem.length <= 0){
jCurItem = jItems.last();
jCurItem.addClass("cur");
keyword = jCurItem.text();
}else{
var index = jCurItem.index();
jCurItem.removeClass("cur");
if(index <= 0){
keyword = value;
}else{
jCurItem = jItems.eq(index-1);
jCurItem.addClass("cur");
keyword = jCurItem.text();
}
}
jthis.val(keyword);
}else{
if(jCurItem.length <= 0){
jCurItem = jItems.first();
jCurItem.addClass("cur");
keyword = jCurItem.text();
}else{
var index = jCurItem.index();
jCurItem.removeClass("cur");
if(index + 1 >= jItems.length){
keyword = value;
}else{
jCurItem = jItems.eq(index+1);
jCurItem.addClass("cur");
keyword = jCurItem.text();
}
}
jthis.val(keyword);
}
}
}
}
/*event handler*/
$.fn.unintell = function(){
remove();
}
$(document).unbind({click:window.intellDocumentClick,keydown:window.intellDocumentKeydown})
.bind({click:window.intellDocumentClick,keydown:window.intellDocumentKeydown});
jthis.focus(function(){
_focusCount++;
if(_focusCount > 1){
return;
}
if(window.intellObj.jthis && jthis !== window.intellObj.jthis){
setIntellObj(null);
}
var keyword = attrValue();
if(keyword === _dftOpts.defaultValue){
keyword = "";
attrValue(keyword);
}
if(keyword || _dftOpts.isEmptyRequest){
sendRequest();
}
})
jthis.blur(function(){
_focusCount = 0;
if(!attrValue()){
attrValue(_dftOpts.defaultValue);
}
})
jthis.keyup(function(e){
if(e.keyCode === 38 || e.keyCode === 40){
return;
}
var keyword = attrValue();
if(!keyword){
remove();
window.intellObj.value = _value = "";
return;
}
if(keyword !== _value){
window.intellObj.value = _value = keyword;
sendRequest();
}
}); return initBox(); /*function*/
function initBox(){
attrValue(_dftOpts.defaultValue);
return jthis;
}
function initIntell(){
generate();
register();
setIntellObj({jthis:jthis,jResult:jResult});
}
function generate(){
var offset = _dftOpts.aligner.offset();
var width = _dftOpts.width ? _dftOpts.width : _dftOpts.aligner.width();
jResult = $("<ul>",{"class":"intellResult"});
jResult.width(width).css({"position":"absolute","left":offset.left,"top":offset.top + jthis.outerHeight()});
$("body").append(jResult);
if(_dftOpts.maxHeight > 0){
jResult.height(_dftOpts.maxHeight).css("overflowY","scroll");
}
}
function remove(){
if(jResult){
jResult.remove();
jResult = null;
}
}
function register(){
jResult.on("click","li",function(){
var jItem = $(this);
var index = jItem.index();
var keyword = jItem.text();
attrValue(keyword);
_value = keyword;
if(_event.itemClick){
_event.itemClick({"jthis":jthis,"jItem":jItem,"item":_cache[index]});
}
}).on("mouseenter","li",function(){
$(this).siblings("li").removeClass("cur").end().addClass("cur");
}).on("mouseleave","li",function(){
$(this).removeClass("cur");
});
}
function setIntellObj(obj){
if(!obj){
if(window.intellObj.jResult){
window.intellObj.jResult.remove();
}
window.intellObj.jthis = null;
window.intellObj.jResult = null;
}else{
window.intellObj.jthis = obj.jthis;
window.intellObj.jResult = obj.jResult;
}
}
function sendRequest(){
var data;
if(_event.setData){
data = _event.setData({"jthis":jthis});
}
$.ajax({
url:_dftOpts.url,
data:data,
cache:_ajax.cache,
timeout:_ajax.timeout,
beforeSend:function(xhr){
if(_event.beforeSend){
_event.beforeSend(xhr);
}
},
success:function(data){
remove();
showData(data);
},
error:null
});
}
function showData(data){
data = $.trim(data) ? $.parseJSON(data) : data;
if(_event.beforeRender){
var rs = _event.beforeRender({"jthis":jthis,"data":data});
if(rs === false){
return;
}
if(rs !== undefined){
data = rs;
}
}
if(!data){
return;
}
var jItem,jA,jSpan,hasProp,item,text,otherTexts,isRender,index;
var list = $.isArray(data) ? data : [data];
var length = list.length;
length = length > _dftOpts.itemNumber ? _dftOpts.itemNumber : list.length;
if(length <= 0){
return;
}
initIntell();
_cache.length = 0;
hasProp = list[0][_dftOpts.property];
for(var i=0;i<length;i++){
item = list[i];
if(item === null || item === undefined){
continue;
}
text = hasProp ? item[_dftOpts.property] : item;
text = $.trim(text.toString());
if(text === ""){
continue;
}
jItem = $("<li>",{"class":"intellResult_item"});
jA = $("<a>",{"title":text}).appendTo(jItem);
jSpan = $("<span>").appendTo(jA);
index = text.toLowerCase().indexOf(_value.toLowerCase());
otherTexts = splitText(text,_value,index);
if(otherTexts){
jSpan.text(text.substr(index,_value.length));
if(otherTexts.length > 1){
$("<b>",{"text":otherTexts[0]}).insertBefore(jSpan);
$("<b>",{"text":otherTexts[1]}).insertAfter(jSpan);
}else{
if(index === 0){
$("<b>",{"text":otherTexts[0]}).insertAfter(jSpan);
}else{
$("<b>",{"text":otherTexts[0]}).insertBefore(jSpan);
}
}
}else{
jSpan.text(text);
}
isRender = true;
if(_event.itemBeforeRender){
isRender = _event.itemBeforeRender({"jthis":jthis,"jItem":jItem,"item":item});
}
if(isRender !== false){
jResult.append(jItem);
if(_event.itemAfterRender){
_event.itemAfterRender({"jthis":jthis,"jItem":jItem,"item":item});
}
}
_cache.push(item);
}
if(_event.endRender){
_event.endRender({"jthis":jthis});
}
jResult.show();
}
function attrValue(value){
if(!value && value != ""){
return $.trim(jthis.val());
}
jthis.val(value);
}
function splitText(text,value,index){
var tlength = text.length;
var vlength = value.length;
if(index === -1){
return null;
}
if(index === 0){
if(index + vlength >= tlength){
return null;
}
return [text.substr(index + vlength)];
}
if(index + vlength >= tlength){
return [text.substr(0,index)];
}
return [text.substr(0,index),text.substr(index + vlength)];
}
}
})(window,jQuery);

样式

.intellResult{margin:0;padding:0;background:#fff;border:1px solid #b6b6b6;clear:both;z-index:999;display:none;}
.intellResult li{margin:0;padding:0;padding:5px 15px;height:20px;line-height:20px;overflow:hidden;text-overflow:ellipsis;cursor:pointer;white-space:nowrap;}
.intellResult li.cur{background:#E5E0E0;}

福利到~分享一个基于jquery的智能提示控件intellSeach.js的更多相关文章

  1. 一个基于jquery的智能提示控件intellSeach.js

    一.需求 我们经常会遇到[站内搜索]的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示.例如:某公司人事管理系统,想搜索李XX,只要输入“李”,系统自然会提示一些姓李的员工,这样方便用户 ...

  2. jquery的智能提示控件

    福利到~分享一个基于jquery的智能提示控件intellSeach.js   一.需求 我们经常会遇到[站内搜索]的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示.例如:某公司人事管 ...

  3. 基于Jquery的文本提示控件 poshytip

    Html中,如设置了title的属性,则当鼠标在该对象上面短暂的停留时,会显示预设的文本提示,但,这些效果只会短暂的显示,一会就会消失,又要重新把鼠标移出再移回来才被显示,样式也无法重写,实在是恼人之 ...

  4. 分享一个基于长连接+长轮询+原生的JS及AJAX实现的多人在线即时交流聊天室

    实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询.长连接+长轮询.基于第三方插件(如FLASH的Socket),而如果是HTML5,则比较简单,可以直接使用WebSoc ...

  5. 打造基于jQuery的日期选择控件

    终于把jQuery拼写正确了哈,哈哈javascript也是区分大小写的,所以确实不能写错,今天我来和大家分享的是日期选择控件的实现,功能也许不够强大,但是能够满足需求. 我之前也写过(正确的说是改过 ...

  6. 分享一个Winform里面的HTML编辑控件Zeta HTML Edit Control,汉化附源码

    我们知道,Web开发上有很多HTML的编辑控件,如FCKEditor.CKEditor.kindeditor等等,很多都做的很好,而虽然Winform里面有WebBrowser控件,但是默认这个控件是 ...

  7. 基于JQuery EasyUI的WebMVC控件封装(含源码)

    JQuery EasyUI类库,大家不会陌生,出来已经有很多年了.个人感觉还是很好用的,作者更新频率也很快,bug也及时修复. 最近在整理以前的代码,找到了这个组件,它是将EasyUI组件封装成MVC ...

  8. 分享一个 C# Winfrom 下的 OutlookBar 控件的使用

    最近在上网的时候,发现了这个C# 下的 OutlookBar 控件,看了一下感觉还真不错,特此记录一下. using System; using System.Drawing; using Syste ...

  9. jquery自动生成分页控件 - pagetest.js

    /* pagenum:当前页数 theallnum:总条数 themeiye:每页显示多少条 */ function pagetest(pagenum, theallnum, themeiye) { ...

随机推荐

  1. 2015元旦来个炫的html5特效

    效果网址:http://keleyi.com/keleyi/phtml/html5/5.htm 代码: <!DOCTYPE html> <html xmlns="http: ...

  2. 原生JS实战:写了个斗牛游戏,分享给大家一起玩!

    本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5869953.html 该程序是本人的个人作品,写的不好,未经本人允许,请 ...

  3. ABAP程序互调用:SUBMIT、CALL TRANSACTION、LEAVE TO TRANSACTION

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  4. Linux0.11内核--文件系统理论知识

    1.文件系统介绍 一个简单的文件系统大致需要这么几个要素: ● 要有地方存放Metadata: ● 要有地方记录扇区的使用情况: ● 要有地方来记录任一文件的信息,比如占用了哪些扇区等: ● 要有地方 ...

  5. xcode8打包ipa文件, application loader上传成功,但是iTunes Connect不显示构建版本

    最近更新的Xcode8.今天提交新项目时.按照以往的流程走 Xcode 编译ipa文件.applicaiton loader提交成功 但是.iTunes connect构建版本不显示.非常疑惑.平时等 ...

  6. UITextField的代理方法:textField:shouldChangeCharactersInRange:replacementString

    原文链接:http://www.cnblogs.com/zhanggui/p/6101813.html 这个我在开发的过程中用到的次数最多,因此这里就简单对其进行分析.先看看Command+点击 弹出 ...

  7. CSS3-04 样式 3

    前言 关于 HTML/CSS 的博客也写了几篇了.该系列博客主要介绍 HTML 和 CSS 的基础,尚未过多的涉及 HTML5 和 CSS3 (即 HTML/CSS 进阶)的内容.这些博客是按照一定的 ...

  8. 基于Ruby的Watir-WebDriver自动化测试方案

    Watir-WebDriver       —— 软件测试的自动化时代 QQ群:160409929 自动化测试方案书 系统架构 该自动化测试框架分三个模块:Test用例.Control控制层.Tool ...

  9. $是对string.Format的简化

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. StringUtils工具类

    StringUtils源码,使用的是commons-lang3-3.1包.下载地址 http://commons.apache.org/lang/download_lang.cgi 以下是String ...