• autocomplete实现联想输入,自动补全


    jQuery.AutoComplete是一个基于jQuery的自动补全插件。借助于jQuery优秀的跨浏览器特性,可以兼容Chrome/IE/Firefox/Opera/Safari等多种浏览器。

    特性一览:

      • 支持补全列表的宽度设定。
      • 支持补全列表的最大高度设定。
      • 支持补全列表的行数限制。
      • 支持补全列表的显示位置及方向的设定。
      • 支持自定义匹配规则。
      • 支持匹配文本的渲染。
      • 支持自定义匹配文本的渲染样式。
      • 支持补全列表的样式设定。
      • 支持自定义补全列表项的创建。
      • 支持多种数据源。
      • 支持'json'和'xml'两种数据格式。
      • 支持异步处理。
      • 支持错误调试。
      • 支持jQuery1.7.1+。

    先看效果图:

    上图是通过ajax请求服务器返回的数据。下面简单介绍如何使用。

    一、如何使用:

       引入jquery.autocomplete.js和jquery.autocomplete.css文件到你的页面中。

    二、参数说明:

    autocomplete的参数比较丰富。这里我不全部进行介绍。大家自行去看api文档。
    $("#tt").AutoComplete({
        'data': ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten',     'Eleven', 'Twelve']
    });
    

      data可以是数组,也可以是url,但url返回的数据必须是数组。

     

    三、示例:

      1、本地数据:
    html代码:
    <input type="text" id="tt" value="" class="text" />
     
    javascript代码:
    $(function(){
    
        $("#tt").AutoComplete({
            'data':['Cambodia', 'Cameroon', 'Canada', 'Cape-Verde', 'Cayman-Islands', 'Central-African-Republic', 'Chad', 'Chile', 'China', 'Colombia', 'Commonwealth', 'Comoros', 'Costa-Rica', "Cote-d'Ivoire", 'Croatia', 'Cuba', 'Cyprus', 'Czech-Republic'],
        });
    
    })

    注意data是有引号的。

    2、ajax请求:

    html代码:
    <input type="text" id="company" value="" class="text" />

    javascript代码:

    $(function(){
        $("#tt").AutoComplete({
            'data':'http://localhost/test/suggestCom',
        });
    })

    服务端返回数据格式:

    ["u5317u4eacu73b0u4ee3","u5317u4eacu57ceu5efau96c6u56e2u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu5efau5de5u96c6u56e2u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu9996u90fdu65c5u6e38u96c6u56e2u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu533bu836fu96c6u56e2u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu4e00u8f7bu63a7u80a1u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu91d1u9685u96c6u56e2u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu71d5u4eacu5564u9152u96c6u56e2u516cu53f8","u5317u4eacu5e02u71c3u6c14u96c6u56e2u6709u9650u8d23u4efbu516cu53f8","u5317u4eacu4f4fu603bu96c6u56e2u6709u9650u8d23u4efbu516cu53f8"]

    服务端的代码:(以ThinkPHP示例)

    public function suggestCom(){
            $wd = $_GET['keyword'];
            $keywords = $wd;
        
            $company_model = M('Company');
        
            $res = $company_model->where("name like '%".$keywords."%' or abbr like '%".$keywords."%' ")->limit(10)->select();
            foreach($res as $v){
                $suggestions[]= $v['name'];
            }
        
            echo json_encode($suggestions);
        }

    注意默认是GET过来的数据,名称是keyword,返回数据是和本地data一致的。

    附上jquery.autocomplete.js和jquery.autocomplete.css文件代码:

    jquery.autocomplete.js

    /*
    * jQuery.autocomplete.js (v1.1.2)
    * authored by nswish (nswish@gmail.com)
    * jQuery 1.7.1+ support
    * compatible: ie/chrome/firefox/opera/safari
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    (function($){
        $.fn.extend({
            'AutoComplete': function(option){
                return this.each(function(){
                    if (!(this && this.tagName === 'INPUT' && this.type === 'text')) return;
    
                    if(this.controller)
                        this.controller.setOption(option);
                    else {
                        if($.isPlainObject(option))
                            this.controller = new Controller(this, option);
                    }
                });
            }
        });
    
        // ------- Construct Method Here -------------
        var Controller = function(input, option){
            this.option = $.extend(false, {
                // style
                'width': 320,                                   // number, string 'auto'
                'maxHeight': null,                              // number
                'itemHeight': null,                             // number
                'listStyle': 'normal',                          // string 'normal', 'iconList', 'custom'
                'listDirection': 'down',                        // string 'down' or 'up'
                // data
                'data': [],                                     // array, string, function
                'ajaxDataType': 'json',                         // string 'json' or 'xml'
                'ajaxParams': {},                               // function, string, object
                'ajaxTimeout': 3000,                            // number
                'ajaxType': 'GET',                              // string 'GET' or 'POST'
                'maxItems': 20,                                 // number
                // event
                'matchHandler': defaultMatchHandler,            // function
                'emphasisHandler': defaultEmphasisHandler,      // function
                'createItemHandler': null,                      // function
                'beforeLoadDataHandler': null,                  // function
                'afterSelectedHandler': null,                   // function
                // behavior
                'async': false,                                 // bool
                'emphasis': true,                               // bool
                // debug
                'onerror': null                                 // function
            }, option);    
    
            _setupInputView.apply(this, [input]);
            _setupSearchView.apply(this);
        };
    
        // ------- Private Method Here -------------
        var _setupInputView = function(input){
            var that = this;
    
            this.inputView = $(input);
    
            this.inputView
            .attr('autocomplete', 'off') // disable IE's autocomplete feature
            .keyup(this._keyup = function(event){
                switch(event.keyCode){
                    case 13: // enter
                    case 16: // shift
                    case 17: // ctrl
                    case 37: // left
                    case 38: // up
                    case 39: // right
                    case 40: // down
                        break;
                    case 27: // esc
                        _emptySearchView.apply(that);
                        break;
                    default:
                        if(that.option.async){
                            setTimeout(function(){
                                _search.apply(that);
                            }, 0);
                        } else {
                            _search.apply(that);
                        }
                }
            })
            .keydown(this._keydown = function(event){
                switch(event.keyCode){
                    case 38: // up
                        _move.apply(that, ['up']);
                        break;
                    case 40: // down
                        _move.apply(that, ['down']);
                        break;
                    case 13: // enter
                        var isSearchViewVisible = that.searchView.is(':visible');
                        _select.apply(that);
                        if(isSearchViewVisible)
                            return false;
                        break;
                }
            })
            .blur(this._blur = function(){
                $(document).one('click', function(){
                    _emptySearchView.apply(that);
                });
            });
        };
    
        var _setupSearchView = function(){
            var that = this;
    
            this.searchView = $("<div class='ac'><ul></ul></div>")
            .appendTo(document.body)
            .on('mouseenter', 'li', function(){
                that.searchView.find("li.selected").removeClass("selected");
                $(this).addClass('selected');
            })
            .on('mouseleave', 'li', function(){
                $(this).removeClass('selected');
            })
            .on('click', 'li', function(){
                _select.apply(that);
                _emptySearchView.apply(that);
            })
            .css('font-size', this.inputView.css('font-size'));
    
            $(window).resize(function(){
                _locateSearchView.apply(that);
            });
        };
    
        var _createItems = function(result){
            var that = this,
                container = this.searchView.find('ul').empty();
    
            if ($.inArray(this.option.listStyle, ['normal', 'iconList', 'custom']) == -1) {
                throw ['遇到未知的listStyle参数!'];
            };
    
            $.each(result, function(index, data){
                var item = $("<li><div></div></li>").appendTo(container).addClass(that.option.listStyle).data("data", data).find("div");
    
                switch(that.option.listStyle){
                    case 'normal':
                        item.append("<span>"+data.label+"</span>");
                        break;
                    case 'iconList':
                        var img = $("<img></img>").attr('src', data.image);
                        item.append($("<div></div>").append(img)).append("<span>"+data.label+"</span>");
                        break;
                    case 'custom':
                        item.append(that.option.createItemHandler.apply(that, [index, data]));
                    case 'default':
                        break;
                }
    
                if(that.option.itemHeight > 0){
                    item.height(that.option.itemHeight).css('max-height', that.option.itemHeight);
                }
            });
        };
    
        var _locateSearchView = function(){
            if(this.option.listDirection === 'down'){
                var top = this.inputView.offset().top + this.inputView.outerHeight();
            } else if(this.option.listDirection === 'up'){
                var top = this.inputView.offset().top - this.searchView.outerHeight();
            } else {
                throw '遇到未知的listDirection参数!';
            }
    
            var left = this.inputView.offset().left;
            this.searchView.css("top", top+"px").css("left", left+"px");
        };
    
        var _calcWidth = function(){
            if(typeof(this.option.width) === 'string' && this.option.width.toLowerCase() === 'auto'){
                return this.inputView.outerWidth() - 2;
            } else if(typeof(this.option.width) === 'number'){
                return this.option.width;
            } else {
                throw '遇到未知的width参数!';
            }
        }
    
        var _showSearchView = function(result){
            var that = this;
    
            if(this.option.listDirection === 'up')
                result = result.reverse();
        
            try{
                _createItems.apply(that, [result]);//console.log("length="+this.searchView.find('li').size());
    
                if(this.option.maxHeight > 0){
                    this.searchView.css('max-height', this.option.maxHeight+"px");
                    if($.browser.msie){
                        this.searchView.css("height", this.searchView.height() > this.option.maxHeight ? this.option.maxHeight+"px" : "auto");
                    }
                }
    
                // 定位补全列表
                _locateSearchView.apply(this);
    
                // 计算并设定补全列表的宽度
                this.searchView.css("width", _calcWidth.apply(this)+'px');
    
            } catch(ex) {
                _error.apply(this, [ex+'']);
                return;
            }
    
            this.searchView.show();
    
            _move.apply(this, [this.option.listDirection]);
        };
    
        var _emptySearchView = function(){
            this.searchView.find('ul').empty();
            this.searchView.hide();
        };
    
        var _move = function(dir){
            var selected = this.searchView.find('li.selected');
    
            if (selected.size()) 
                var nextSelected = dir === 'up' ? selected.prev() : selected.next();
            else
                var nextSelected = dir === 'up' ? this.searchView.find('li').last() : this.searchView.find('li').first();
            
            if(nextSelected.size()){
                this.searchView.find('li').removeClass('selected');
                nextSelected.addClass("selected");
    
                var itemHeight = nextSelected.outerHeight();
                var itemTop = nextSelected.position().top;
                if(itemHeight + itemTop > this.searchView.height())
                    this.searchView.scrollTop(this.searchView.scrollTop() + itemTop + itemHeight - this.searchView.height());
                else if(itemTop < 0)
                    this.searchView.scrollTop(this.searchView.scrollTop() + itemTop);
            }
        };
    
        var _select = function(){
            var that = this,
                selected = this.searchView.find('li.selected');
            
            if (selected.size()) {
                var data = selected.data('data');
    
                this.inputView.val(data.value);
    
                if ($.isFunction(this.option.afterSelectedHandler)) {
                    try{
                        this.option.afterSelectedHandler.apply(that, [data]);
                    } catch(e) {
                        _error.apply(this, ['调用afterSelectedHandler错误:'+e]);
                        return;
                    }
                }
    
                _emptySearchView.apply(this);
            }
        };
    
        var _ajaxSend = function(keyword){
            jQuery.support.cors = true;
            var that = this,
                data = [],
                ajaxOption = {
                    'async': false,
                    'dataType': that.option.ajaxDataType,
                    'type': that.option.ajaxType,
                    'timeout': this.option.ajaxTimeout,
                    'success': function(theData, textStatus, jqXHR){
                        if (that.option.ajaxDataType === 'xml') {
                            $(theData).find('item').each(function(){
                                var item = {
                                    'value': $(this).text(),
                                    'label': $(this).text()
                                };
    
                                for (var i=0; i<this.attributes.length; i++) {
                                    var key = this.attributes[i].nodeName,
                                        value = this.attributes[i].nodeValue;
    
                                    item[key] = value;
                                };
    
                                data.push(item);
                            });
                        } else if(that.option.ajaxDataType === 'json') {
                            data = theData;
                        } else {
                            throw '遇到未知的ajaxDataType参数!';
                        }
                    },
                    'error': function(jqXHR, textStatus, errorThrown){
                        throw errorThrown;
                    }
                };
    
            if ($.isPlainObject(this.option.ajaxParams)) {
                ajaxOption['data'] = $.extend(false, {'keyword': keyword}, this.option.ajaxParams);
            } else if ($.isFunction(this.option.ajaxParams)) {
                ajaxOption['data'] = $.extend(false, {'keyword': keyword}, this.option.ajaxParams.apply(this, [keyword]));
            } else if (typeof(this.option.ajaxParams) === 'string') {
                ajaxOption['data'] = "keyword=" + keyword + "&" + this.option.ajaxParams;
            } else {
                throw '遇到未知的ajaxParams参数!';
            }
    
            $.ajax(this.option.data, ajaxOption);
    
            return data;
        };
    
        var _search = function(){
            var that = this,
                keyword = this.inputView.val(),
                data = [],
                loadDataFlag = true,
                result = [];
    
            if($.trim(keyword).length == 0){
                _emptySearchView.apply(that);
                return;
            }
    
            // invoke beforeLoadDataHandler if exists
            if ($.isFunction(this.option.beforeLoadDataHandler)) {
                try{
                    loadDataFlag = this.option.beforeLoadDataHandler.apply(this, [keyword]);
                } catch(e) {
                    _error.apply(this, ['调用beforeLoadDataHandler错误:'+e]);
                    return;
                }
            }
    
            if (loadDataFlag){
                if ($.isArray(this.option.data)) {
                    data = this.option.data;
                } else if ($.isFunction(this.option.data)) {
                    try{
                        data = this.option.data.apply(this, [keyword]);
                    } catch(e) {
                        _error.apply(this, ['调用data错误:'+e]);
                        return;
                    }
                } else if (typeof(this.option.data) === 'string') {
                    try{
                        data = _ajaxSend.apply(this, [keyword]);
                    } catch(e) {
                        _error.apply(this, ['Ajax错误:'+e]);
                        return;
                    }
                } else {
                    _error.apply(this, ['遇到未知的data参数!']);
                    return;
                }
            }
    
            $.each(data, function(index, value){
                if(that.option.maxItems > 0 && result.length >= that.option.maxItems)
                    return false;
    
                if($.isPlainObject(value)){
                    var item = $.extend(false, {}, value);
                } else if(typeof(value) === 'string') {
                    var item = {'label': value, 'value': value, 'image': value};
                } else {
                    _error.apply(that, ['数据源Item类型错误!']);
                    return false;
                }
    
                if(that.option.matchHandler.apply(that, [keyword, item])){
                    result.push(item);
                }
            });
    
            if(keyword == this.inputView.val()){
                if(result.length > 0)
                    _showSearchView.apply(this, [result]);
                else
                    _emptySearchView.apply(this);
            }
        };
    
        var _error = function(msg){
            if($.isFunction(this.option.onerror)){
                this.option.onerror.apply(this, [msg]);
            }
        };
    
        // ------- Public Method Here -------------
        Controller.prototype.setOption = function(option){
            if ($.isPlainObject(option)) {
                this.option = $.extend(false, this.option, option);
            } else if(typeof(option) === 'string'){
                switch(option){
                    case 'destroy':
                        this.destroy();
                        break;
                    case 'show':
                        this.show();
                        break;
                    default:
                        _error.apply(this, ['未知的AutoComplete参数!']);
                        return;
                }
            } else {
                _error.apply(this, ['未知的AutoComplete参数类型!']);
                return;
            }
        };
    
        Controller.prototype.destroy = function(){
            this.searchView.remove();
            this.inputView.unbind('keyup', this._keyup).unbind('keydown', this._keydown).unbind('blur', this._blur);
            delete this.inputView.get(0).controller;
        };
    
        Controller.prototype.show = function(){
            if(this.option.async){
                setTimeout(function(){
                    _search.apply(this);
                }, 0);
            } else {
                _search.apply(this);
            }    
        };
    
        // ------- Default Handler Function Here -------------
        var defaultMatchHandler = function(keyword, data){
            var regex = RegExp(keyword.replace(/([.?*+^$[]\(){}|-])/g, "\$1"), 'i');
            if(this.option.emphasis && $.isFunction(this.option.emphasisHandler))
                this.option.emphasisHandler.apply(this, [keyword, data]);
            return regex.test(data.value);
        };
    
        var defaultEmphasisHandler = function(keyword, data){
            var regex = RegExp("("+keyword.replace(/([.?*+^$[]\(){}|-])/g, "\$1")+")", 'ig');
            data.label = data.label.replace(regex, "<em>$1</em>");
        };
    
    })(jQuery);
    View Code

    jquery.autocomplete.css

    /*
    * jQuery.autocomplete.css (v1.1.0)
    * authored by nswish (nswish@gmail.com)
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    div.ac { 
        border-style: solid;
        border-width: 1px;
        border-color: gray;
        position: absolute;
        display: none;
        overflow: auto;
    }
    
    div.ac > ul {
        margin: 0px;
        padding: 0px;
    }
    
    div.ac > ul > li {
        margin: 0px;
        list-style-type: none;
        background-color: white;
        word-break: break-all;
        font-family: helvetica, arial, "Courier New", sans-serif;
    }
    
    div.ac > ul > li > div {
        display: table-row;
        width: 100%;
    }
    
    div.ac > ul > li > div em {
        background-color: #B0E2FF;
        font-style: normal;
    }
    
    div.ac > ul > li.normal {
        padding: 2px 0px 2px 2px;
    }
    
    div.ac > ul > li.normal > div > span{
        display: table-cell;
        vertical-align: middle;
    }
    
    div.ac > ul > li.iconList {
        padding: 0px 0px 0px 2px;
    }
    
    div.ac > ul > li.iconList > div > div {
        display: table-cell;
        vertical-align: middle;
        padding-right: 5px;
    }
    
    div.ac > ul > li.iconList > div > div > img {
        display: table;
        display: table-cell9;
    }   
    
    div.ac > ul > li.iconList > div > span {
        display: table-cell;
        vertical-align: middle;
    }
    
    div.ac > ul > li.selected {
        background-color: #DCDCDC;
    }
    View Code

    页面html代码:

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Jquery实现仿搜索引擎文本框自动补全插件 - autocomplete</title>
    
    
    <script src="__PUBLIC__/dwz/js/jquery-1.7.min.js" type="text/javascript"></script>
    <script src="__PUBLIC__/autocomplete/jquery.autocomplete.js?v=2"></script>
    <link rel="stylesheet" href="__PUBLIC__/autocomplete/jquery.autocomplete.css" type="text/css" />
    <script type="text/javascript">
    $(function(){
    
        $("#tt").AutoComplete({
            'data':'__MODULE__/test/suggestCom2',
        });
    
    })
    </script>
    
    </head>
    <body>
    
    <style type="text/css">
    *{margin:0;padding:0;list-style-type:none;}
    a,img{border:0;}
    .demo{width:720px;margin:30px auto;}
    .demo h2{font-size:16px;color:#3366cc;height:30px;}
    .demo li{float:left;}
    .text,.button{background:url(http://su.bdimg.com/static/superpage/img/spis_031ddf34.png) no-repeat;}
    .text{width:529px;height:22px;padding:4px 7px;padding:6px 7px 2px9;font:16px arial;border:1px solid #cdcdcd;border-color:#9a9a9a #cdcdcd #cdcdcd #9a9a9a;vertical-align:top;outline:none;margin:0 5px 0 0;}
    .button{width:95px;height:32px;padding:0;padding-top:2px9;border:0;background-position:0 -35px;background-color:#ddd;cursor:pointer}
    </style>
    
    <div class="demo">
        <h2>autocomplete联想输入测试</h2>
        <form action="" method="post" name="searchform" id="searchform" class="searchinfo">
            <ul>
                <li><input type="text" id="tt" value="" class="text" /></li>
                <li><input type="submit" value="搜索" class="button" /></li>
            </ul>
        </form>
    </div>
    
    </body>
    </html>
    View Code
  • 相关阅读:
    7-4 找出不是两个数组共有的元素(20 分)
    7-2 删除重复字符(20 分)
    7-1 兔子繁衍问题(15 分)
    1018 Public Bike Management (30分) (迪杰斯特拉+dfs)
    PAT 1014 Waiting in Line (30分) 一个简单的思路
    1010 Radix (25分)
    试题编号: 201809-4 试题名称: 再卖菜 记忆化搜索
    试题编号: 201903-3 试题名称: 损坏的RAID5
    CCF 试题编号: 201909-4 试题名称: 推荐系统
    洛谷P3809 后缀数组模板
  • 原文地址:https://www.cnblogs.com/52fhy/p/4456092.html
Copyright © 2020-2023  润新知