福利到~分享一个基于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;}
时间: 2024-08-03 09:15:09

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

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

一.需求 我们经常会遇到[站内搜索]的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示.例如:某公司人事管理系统,想搜索李XX,只要输入“李”,系统自然会提示一些姓李的员工,这样方便用户使用.说白了,就是用户边输入,系统会提示相关的结果:或者,当用户点击搜索框时,就推荐一些内容,如360.百度都会提示今天的主要新闻或搜索量大的内容. jquery 已经有一个这样的插件了,叫 autocomplete, 但我觉得不好用.关于autocomplete的介绍也很多,有兴趣的朋友可以去试试

jquery的智能提示控件

福利到~分享一个基于jquery的智能提示控件intellSeach.js 一.需求 我们经常会遇到[站内搜索]的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示.例如:某公司人事管理系统,想搜索李XX,只要输入“李”,系统自然会提示一些姓李的员工,这样方便用户使用.说白了,就是用户边输入,系统会提示相关的结果:或者,当用户点击搜索框时,就推荐一些内容,如360.百度都会提示今天的主要新闻或搜索量大的内容. jquery 已经有一个这样的插件了,叫 autocomplete, 但我

福利到~分享一个基于jquery的分页控件

前台分页控件有很多,以下是我的实现.默认情况下,点击页码会像博客园一样,在url后面加上"#p页码". 有2个参数需要注意: beforeRender: 在每个页码项呈现前会被调用,参数为页码的jQuery对象.这个时候我们可以在呈现前做一些处理,例如增加自己的属性等.默认情况下,点击页码,会在url后面加上“#p页码”,这样的url并不会刷新页面.如果我们需要刷新页面,例如url为,"default.aspx?index=页码",就可以在这个回调函数里处理. ca

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

我们知道,Web开发上有很多HTML的编辑控件,如FCKEditor.CKEditor.kindeditor等等,很多都做的很好,而虽然Winform里面有WebBrowser控件,但是默认这个控件是不允许编辑内容的,可以显示网页而已.Winform开发里面,有些使用RichTextBox控件来编辑HTML,也有一些结合WebBrowser控件来实现内容的编辑,其中我觉得做的最好的应该是Zeta HTML Edit Control(http://www.codeproject.com/Artic

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

最近在上网的时候,发现了这个C# 下的 OutlookBar 控件,看了一下感觉还真不错,特此记录一下. using System; using System.Drawing; using System.Windows.Forms; namespace OutLookBarDemo { internal class BandTagInfo { public OutlookBar outlookBar; public int index; public BandTagInfo(OutlookBar

jWriter一个基于jQuery的阅读写作网站的效果库

看了一下据上次更新已经四个月了,时间过的好快.自从上次面试前端岗时js的能力遭到深深的鄙视后,就在补js的坑了.先是各种看书,接着是期末考试,然后家里有事又耽搁了.在此期间想把用来练手的网站的前端部分重构一下,于是手写了一些jQuery的效果,也就是jWriter了.话说扔了几个月又捡起来的结果就是,看书时都感觉清楚无比的方法什么的全部都忘了,三天不练手生,真理啊. jWriter,一个基于jQuery的阅读写作网站的效果库,用到了部分js原生代码不过都有注释.全部代码都没进行封装过,看起来可能

一个基于jQuery的弹出层插件XYTips

效果预览:http://www.juheweb.com/js/tc/80.html 标签: jQuery [1].[代码] [JavaScript]代码 跳至 [1] ? 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

[UWP]分享一个基于HSV色轮的调色板应用

原文:[UWP]分享一个基于HSV色轮的调色板应用 1. 前言 上一篇文章介绍了HSV色轮,这次分享一个基于HSV色轮的调色板应用,应用地址:ColorfulBox - Microsoft Store 2. 功能 ColorfulBox是Adobe 色轮的简单模仿,只实现了最基本的功能,UI也没那么好看,也没用MVVM框架. 2.1 HSV色轮 这个应用最好玩的地方在于分布于HSV色轮上的各个点(ColorPoint)以及可以通过拖动它们改变颜色.ColorPoint的基本结构如下(不是完整代码

jQuery打造智能提示插件二(可编辑下拉框)

在上一篇 jQuery打造智能提示插件 上改进,增加下拉按钮,修复点击下拉区域外不隐藏BUG 效果 下拉按钮素材: js封装,注意红色部分为BUG修复,然后传入boxwidth不带px: /* /// <reference path="jquery-autocomplete2.0.js" /> zhangs 20140516 */ (function($) { $.fn.combox = function(options) { var KEY = { UP: 38, DOW