• 福利到~分享一个基于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:"请输入关键字...",        
            $("#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:"",//默认值
                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;}
    
  • 相关阅读:
    基础
    条件语句/变量和基本数据类型
    编程语言介绍
    asp.net中log4net使用方法
    web布到服务器上出错
    《转》IEnumerable、IEnumerator两个接口的认识
    异步ADO.NET
    Session的使用
    AJAX参数及各种HTTP状态值
    简易的抓取别人网站内容
  • 原文地址:https://www.cnblogs.com/4littleProgrammer/p/4791819.html
Copyright © 2020-2023  润新知