蒙国造博客

JQuery UI组合框自动补全功能改进版(即时全部显示+input内容保存)

JQuery UI Autocomplete(自动补全)功能在input前端设计中非常有用,最近一个项目正好用到,仔细研究了下组合框(combobox)的自动补全部分,官方地址是:https://jqueryui.com/autocomplete/#combobox。 官方的功能需要一个额外下拉按钮才能显示全部option选项,有些画蛇添足。我的需求是,只要点击输入框,就要显示全部的option选项,并且在输入框里面同时能实现搜索,下面是改进版的功能:

不多说,直接上源码:

<!doctype html>
<html lang=en>
<head>
    <meta charset=utf-8>
    <title>jQuery UI 自动完成(Autocomplete) - 组合框(Combobox)</title>
    <link rel=stylesheet href=http://lib.sinaapp.com/js/jquery-ui/1.10.2/themes/smoothness/jquery-ui.min.css>
    <script src=http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js></script>
    <script src=http://lib.sinaapp.com/js/jquery-ui/1.10.2/jquery-ui.min.js></script>

    <script>
    (function( $ ) {
        $.widget( custom.combobox, {
            _create: function() {
                this.wrapper = $( <span> )
                    .addClass( custom-combobox )
                    .insertAfter( this.element );

                this.element.hide();
                this._createAutocomplete();
                this._clickShowAll();
            },

            // 自动补全主功能          
            _createAutocomplete: function() {
                var select = this.element,
                    option = select.children( option ),
                    selectName = select.attr(name),
                    have = false;

                // 如果设置了select 的name属性,则检查保存数据与页面option是否匹配
                if (selectName){
                    var localValue = localStorage.getItem(selectName);
                    option.each(function(){
                        var itemValue = $(this).val();
                        if (itemValue === localValue)
                        {
                            $(this).attr(selected, selected);
                            have = true;
                            return false;
                        }
                    });

                    // 如果没有,则新建一个option标签
                    if ( !have )
                    {
                        $( <option> ).appendTo( select )
                            .val( localValue )
                            .text( localValue )
                            .attr(selected, selected);
                    }
                }

                // option selected 标签的值
                var selected = select.children( :selected ),
                    value = selected.val();

                // 增加 input 标签,并设置属性
                this.input = $( <input> )
                    .appendTo( this.wrapper )
                    .val( value )
                    .attr({ title: })
                    .addClass( custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left )
                    .autocomplete({
                        delay: 0,
                        minLength: 0,
                        source: $.proxy( this, _source )
                    })
                    .tooltip({
                        tooltipClass: ui-state-highlight
                    });

                this._on( this.input, {
                    autocompleteselect: function( event, ui ) {
                        ui.item.option.selected = true;
                        this._trigger( select, event, {
                            item: ui.item.option
                        });
                    },

                    autocompletechange: _removeIfInvalid
                });

            },

            // 点击输入框自动显示所有值
            _clickShowAll: function() {
                var input = this.input,
                wasOpen = false;

                input
                .mousedown(function() {
                    wasOpen = input.autocomplete( widget ).is( :visible );
                })
                .click(function() {
                    input.focus();
                        // 如果已经可见则关闭
                        if ( wasOpen ) {
                        return;
                    }
                    // 传递空字符串作为搜索的值,显示所有的结果
                    input.autocomplete( search,  );
                });
            },

            // 获取子标签的内容
            _source: function( request, response ) {
                var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), i ),
                    option = this.element.children( option );
                response( option.map(function() {
                    var text = $( this ).text(),
                        val = $( this ).val();
                    if ( this.value && ( !request.term || matcher.test(text) ) )
                    return {
                        label: text,
                        value: val,
                        option: this
                    };
                }));
            },

            // 选择之后执行这里 
            _removeIfInvalid: function( event, ui ) {

                var selectName = this.element.attr(name),
                value = this.input.val(),
                valueLowerCase = value.toLowerCase(),
                valid = false,
                // 是否进行检测,如果不检测输入内容的合法性,将该值设置为 true 即可
                checkInvalid = false;

                // 保存数据
                this.saveData = function() {
                    // 如果设置了select的name属性
                    if (selectName){
                        // 存储数据到localStorage
                        localStorage.setItem(selectName, value);
                    }
                }

                // 如果是直接从下拉菜单中选择,或者配置为不进行数据检测,则直接保存数据,并中断执行 
                if(ui.item || !checkInvalid){
                    this.saveData();
                    return;
                } else {
                    // 搜索一个匹配(不区分大小写)
                    this.element.children( option ).each(function() {
                        if ( $( this ).text().toLowerCase() === valueLowerCase ) {
                            this.selected = valid = true;
                            return false;
                        }
                    });

                    // 如果检测通过,则保存数据并中断执行
                    if ( valid ) {
                        this.saveData();
                        return;
                    }

                    // 过滤无效的值功能
                    this.input
                        .val(  )
                        .attr( title, value +  未找到任何结果 )
                        .tooltip( open );
                    this.element.val(  );
                    this._delay(function() {
                            this.input.tooltip( close ).attr( title,  );
                        }, 2500 );
                    this.input.data( ui-autocomplete ).term = ;
                    // 清除存储的数据
                    localStorage.setItem(selectName, );
                }
            },

            _destroy: function() {
                this.wrapper.remove();
                this.element.show();
            }

        });
    })( jQuery );

    $(function() {
        $( .combobox ).combobox();
    });
    </script>
</head>
<body>

<div class=ui-widget>
    <label>您喜欢的编程语言:</label>
    <!-- 注意,如果要保存数据,必须设置select的name属性,多个select时name属性应该是相互不一样的 -->
    <select class=combobox name=lang>
        <option value=>请选择...</option>
        <option value=ActionScript>ActionScript</option>
        <option value=AppleScript>AppleScript</option>
        <!-- 如果不设置value,则会返回option标签中的内容 --> 
        <option>Asp</option>
        <option value=BASIC>BASIC</option>
        <option value=C>C</option>
        <!-- 如果value值和HTML内容不同,点选后会返回value值; -->
        <option value=CPP>C++</option>
        <option value=Clojure>Clojure</option>
        <option value=COBOL>COBOL</option>
        <option value=ColdFusion>ColdFusion</option>
        <option value=Erlang>Erlang</option>
        <option value=Fortran>Fortran</option>
        <option value=Groovy>Groovy</option>
        <option value=Haskell>Haskell</option>
        <option value=Java>Java</option>
        <option value=JavaScript>JavaScript</option>
        <option value=Lisp>Lisp</option>
        <option value=Perl>Perl</option>
        <option value=PHP>PHP</option>
        <option value=Python>Python</option>
        <option value=Ruby>Ruby</option>
        <option value=Scala>Scala</option>
        <option value=Scheme>Scheme</option>
    </select>
</div>

</body>
</html>

因为JqueryJquery UIJquery UI CSS直接使用新浪SAE,所以保存以上代码成一个html文件,然后直接打开就可以看到效果了,如下图:

在输入框里面输入任何内容,然后鼠标点击页面的其他任意位置,这个值就会保存起来了(在本地 localStorage 中)。刷新页面,还是原来保存的内容。YES。。

退出移动版