3

我已经改编了教程中的以下代码,以根据内容过滤 li 元素:

$('#_selectSearch_' + index).keyup(function() {
       var filter = $(this).val();
       if(filter) {
          $('#_selectDrop_' + index).find("li:not(:contains(" + filter + "))").slideUp();
          $('#_selectDrop_' + index).find("li:contains(" + filter + ")").slideDown();
       } else {
          $('#_selectDrop_' + index).find("li").slideDown();
       }
    });

该代码工作得很好,但是在处理大型列表时非常慢,每次按键都会使浏览器停止几秒钟。我一直在环顾四周,得出的结论是,改进这一点的方法是以某种方式缓存列表而不是直接在 DOM 上操作,但不知道如何实现这一点。

4

5 回答 5

1

If your main concern is performance the following code:

  1. caches element containing filter string.
  2. caches li elements.
  3. doesn't show or hide elements that are already in that state.
  4. uses indexOf which is very fast.
  5. if the user types letters under 500 milliseconds apart the showMatches will not run.
var selectSearch = $("#_selectSearch_" + index );
var li = $("#_selectDrop_" + index + " li");
var currentTimeout;

selectSearch.on( "keyup", function( ) {
    if( currentTimeout ) { window.clearTimeout( currentTimeout ) };
    currentTimeout = setTimeout( showMatches, 500 );

});

function showMatches( ) {
    var txt = selectSearch.val();

    for( var i = 0, len = li.length; i < len; i++ ) {

        var content = li[i].textContent ? li[i].textContent : li[i].innerText;

        if( txt && content.indexOf( txt ) > -1) {
            if( li[i].style.display !== "block" ) {
                li[i].style.display = "block";
            }
        } else {
            if( li[i].style.display !== "none" ) {
                li[i].style.display = "none";
            }
        }
    }
}

Fiddle with 400 li elements here

于 2012-11-27T21:41:20.880 回答
1

你可以缓存这个元素$('#_selectDrop_' + index + ' li');

$('#_selectSearch_' + index).keyup(function() {
    var $li = $('#_selectDrop_' + index + ' li');
    var filter = $(this).val();
    if (filter) {
        $li.not(":contains(" + filter + ")").slideUp();
        $li.contains(filter).slideDown();
    } else {
        $li.slideDown();
    }
});​
于 2012-11-27T20:49:50.553 回答
0

我将尝试使用稍微修改(且未经测试)的版本:

$('#_selectSearch_' + index).on('keyup', function() {
    var filter = this.value,
        lis = document.getElementById('_selectDrop_' + index).getElementsByTagName('li'),
        len = lis.length,
        sup = 'textContent' in this;
    if (filter.length) {
        for (var i = len; i--) {
            var text = sup ? lis[i].textContent : lis[i].innerText;
            $(lis[i])[text.indexOf(filter) != -1 ? 'slideDown' : 'slideUp']();
        }
    } else {
        $(lis).slideDown();
    }
});​
于 2012-11-27T21:25:28.670 回答
0
$('#_selectSearch_' + index).keyup(function() {

   var filter = $(this).val();

   // by combining and cacheing all the way to the li
   // we save a lot of time, since it seems that's where you are doing
   // all your searching from

   var selectDrop = $('#_selectDrop_' + index + ' li');

   if (filter) {
      selectDrop.not(':contains("' + filter + '")').slideUp();
      selectDrop.contains(filter).slideDown();
   } 
   else {
      selectDrop.slideDown();
   }
});
于 2012-11-27T20:45:53.450 回答
0
drop = $('#_selectDrop_' + index + ' li');
$('#_selectSearch_' + index).keyup(function() {
   var filter = $(this).val();
   if(filter) {
      drop.find(":not(:contains(" + filter + "))").slideUp();
      drop.find(":contains(" + filter + ")").slideDown();
   } else {
      drop.slideDown();
   }
});

Drop 只会被缓存一次,然后在每次 keyup 时使用。这也使用了尽可能少的find

于 2012-11-27T20:45:18.833 回答