SORU
22 ŞUBAT 2011, Salı


jQuery UI Büyük Seçin Listeleri İle Combobox otomatik tamamlama Çok Yavaş

Burada görüldüğü gibi jQuery UI otomatik tamamlama Combobox değiştirilmiş bir sürümü kullanıyorum: http://jqueryui.com/demos/autocomplete/#combobox

Bu soru uğruna, hadi tam olarak bu kod ^ ^ ^ var

Combobox açılırken, ya düğmesi veya comboboxs Metin Giriş odaklanarak, öğelerin listesini göstermeden önce büyük bir gecikme var. Bu gecikme, seçim listesi daha fazla seçenek olduğunu ne zaman fark daha büyük olur.

Bu gecikme sadece her zaman olur ilk defa meydana gelmiyor.

Bu proje seçim listesi bazı çok büyük (yüzlerce ve yüzlerce öğe) olarak, gecikme/tarayıcı buz gibi kabul edilemez.

Herkes doğru yönde bana gelin bu optimize etmek için olabilir mi? Hatta performans sorunu olabilir?

Bu sorun, komut dosyası öğeleri tam listesini boş bir dize için bir otomatik tamamlama arama yapar (), tüm öğeleri görüntülemek için bir başka yol gösterme yolu ile ilgisi olabilir mi? Belki de tüm düzenli ifade eşleştirme yapmaz tüm öğeleri görüntülemek için bir dava yaygın türü başlamadan önce listesini açmak için olduğu gibi) inşa miyim?

Burada elimi meşgul edecek bir jsfiddle: http://jsfiddle.net/9TaMu/

CEVAP
9 HAZİRAN 2011, PERŞEMBE


Güncel combobox uygulaması ile, tam liste boşaltılır ve yeniden işlenen açılan genişletmek her zaman. Ayrıca boş bir arama tam listesini almak için yapmak zorunda çünkü 0, minLength ayarı ile sıkışmış.

İşte benim kendi uygulama otomatik tamamlama widget uzanan. Benim testlerde 5000 listeler gayet sorunsuz hatta IE 7 ve 8 işleyebilir. Açılan düğmesine tıkladığınız zaman tam listesi sadece bir kez oluşturur ve kullanır. Bu da seçenek minLength = 0 bağımlılığı kaldırır. Ayrıca diziler ile çalışır, ve ajax gibi Kaynak Listesi. Ayrıca eğer birden çok büyük bir liste varsa, widget başlatma arka planda çalışır ve tarayıcı dondurmak değil, yani bir sıraya eklenir.

<script>
(function($){
    $.widget( "ui.combobox", $.ui.autocomplete, 
        {
        options: { 
            /* override default values here */
            minLength: 2,
            /* the argument to pass to ajax to get the complete list */
            ajaxGetAll: {get: "all"}
        },

        _create: function(){
            if (this.element.is("SELECT")){
                this._selectInit();
                return;
            }

            $.ui.autocomplete.prototype._create.call(this);
            var input = this.element;
            input.addClass( "ui-widget ui-widget-content ui-corner-left" );

            this.button = $( "<button type='button'> </button>" )
            .attr( "tabIndex", -1 )
            .attr( "title", "Show All Items" )
            .insertAfter( input )
            .button({
                icons: { primary: "ui-icon-triangle-1-s" },
                text: false
            })
            .removeClass( "ui-corner-all" )
            .addClass( "ui-corner-right ui-button-icon" )
            .click(function(event) {
                // close if already visible
                if ( input.combobox( "widget" ).is( ":visible" ) ) {
                    input.combobox( "close" );
                    return;
                }
                // when user clicks the show all button, we display the cached full menu
                var data = input.data("combobox");
                clearTimeout( data.closing );
                if (!input.isFullMenu){
                    data._swapMenu();
                    input.isFullMenu = true;
                }
                /* input/select that are initially hidden (display=none, i.e. second level menus), 
                   will not have position cordinates until they are visible. */
                input.combobox( "widget" ).css( "display", "block" )
                .position($.extend({ of: input },
                    data.options.position
                    ));
                input.focus();
                data._trigger( "open" );
            });

            /* to better handle large lists, put in a queue and process sequentially */
            $(document).queue(function(){
                var data = input.data("combobox");
                if ($.isArray(data.options.source)){ 
                    $.ui.combobox.prototype._renderFullMenu.call(data, data.options.source);
                }else if (typeof data.options.source === "string") {
                    $.getJSON(data.options.source, data.options.ajaxGetAll , function(source){
                        $.ui.combobox.prototype._renderFullMenu.call(data, source);
                    });
                }else {
                    $.ui.combobox.prototype._renderFullMenu.call(data, data.source());
                }
            });
        },

        /* initialize the full list of items, this menu will be reused whenever the user clicks the show all button */
        _renderFullMenu: function(source){
            var self = this,
                input = this.element,
                ul = input.data( "combobox" ).menu.element,
                lis = [];
            source = this._normalize(source); 
            input.data( "combobox" ).menuAll = input.data( "combobox" ).menu.element.clone(true).appendTo("body");
            for(var i=0; i<source.length; i  ){
                lis[i] = "<li class=\"ui-menu-item\" role=\"menuitem\"><a class=\"ui-corner-all\" tabindex=\"-1\">" source[i].label "</a></li>";
            }
            ul.append(lis.join(""));
            this._resizeMenu();
            // setup the rest of the data, and event stuff
            setTimeout(function(){
                self._setupMenuItem.call(self, ul.children("li"), source );
            }, 0);
            input.isFullMenu = true;
        },

        /* incrementally setup the menu items, so the browser can remains responsive when processing thousands of items */
        _setupMenuItem: function( items, source ){
            var self = this,
                itemsChunk = items.splice(0, 500),
                sourceChunk = source.splice(0, 500);
            for(var i=0; i<itemsChunk.length; i  ){
                $(itemsChunk[i])
                .data( "item.autocomplete", sourceChunk[i])
                .mouseenter(function( event ) {
                    self.menu.activate( event, $(this));
                })
                .mouseleave(function() {
                    self.menu.deactivate();
                });
            }
            if (items.length > 0){
                setTimeout(function(){
                    self._setupMenuItem.call(self, items, source );
                }, 0);
            }else { // renderFullMenu for the next combobox.
                $(document).dequeue();
            }
        },

        /* overwrite. make the matching string bold */
        _renderItem: function( ul, item ) {
            var label = item.label.replace( new RegExp(
                "(?![^&;] ;)(?!<[^<>]*)("   $.ui.autocomplete.escapeRegex(this.term)   
                ")(?![^<>]*>)(?![^&;] ;)", "gi"), "<strong>$1</strong>" );
            return $( "<li></li>" )
                .data( "item.autocomplete", item )
                .append( "<a>"   label   "</a>" )
                .appendTo( ul );
        },

        /* overwrite. to cleanup additional stuff that was added */
        destroy: function() {
            if (this.element.is("SELECT")){
                this.input.remove();
                this.element.removeData().show();
                return;
            }
            // super()
            $.ui.autocomplete.prototype.destroy.call(this);
            // clean up new stuff
            this.element.removeClass( "ui-widget ui-widget-content ui-corner-left" );
            this.button.remove();
        },

        /* overwrite. to swap out and preserve the full menu */ 
        search: function( value, event){
            var input = this.element;
            if (input.isFullMenu){
                this._swapMenu();
                input.isFullMenu = false;
            }
            // super()
            $.ui.autocomplete.prototype.search.call(this, value, event);
        },

        _change: function( event ){
            abc = this;
            if ( !this.selectedItem ) {
                var matcher = new RegExp( "^"   $.ui.autocomplete.escapeRegex( this.element.val() )   "$", "i" ),
                    match = $.grep( this.options.source, function(value) {
                        return matcher.test( value.label );
                    });
                if (match.length){
                    match[0].option.selected = true;
                }else {
                    // remove invalid value, as it didn't match anything
                    this.element.val( "" );
                    if (this.options.selectElement) {
                        this.options.selectElement.val( "" );
                    }
                }
            }                
            // super()
            $.ui.autocomplete.prototype._change.call(this, event);
        },

        _swapMenu: function(){
            var input = this.element, 
                data = input.data("combobox"),
                tmp = data.menuAll;
            data.menuAll = data.menu.element.hide();
            data.menu.element = tmp;
        },

        /* build the source array from the options of the select element */
        _selectInit: function(){
            var select = this.element.hide(),
            selected = select.children( ":selected" ),
            value = selected.val() ? selected.text() : "";
            this.options.source = select.children( "option[value!='']" ).map(function() {
                return { label: $.trim(this.text), option: this };
            }).toArray();
            var userSelectCallback = this.options.select;
            var userSelectedCallback = this.options.selected;
            this.options.select = function(event, ui){
                ui.item.option.selected = true;
                if (userSelectCallback) userSelectCallback(event, ui);
                // compatibility with jQuery UI's combobox.
                if (userSelectedCallback) userSelectedCallback(event, ui);
            };
            this.options.selectElement = select;
            this.input = $( "<input>" ).insertAfter( select )
                .val( value ).combobox(this.options);
        }
    }
);
})(jQuery);
</script>

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Matthew Morrill

    Matthew Morr

    15 EKİM 2011
  • PamtheBlamofficial

    PamtheBlamof

    31 Aralık 2010
  • SamsTech

    SamsTech

    4 NİSAN 2014