你的位置:首页 > Java教程

[Java教程]福利到~分享一个基于jquery的智能提示控件intellSeach.js

一、需求

  我们经常会遇到【站内搜索】的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示。例如:某公司人事管理系统,想搜索李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;}