13

我有一个自动完成表单,用户可以在其中输入一个术语,它会隐藏所有<li>不包含该术语的元素。

<li>我最初使用 jQuery遍历所有内容each并应用于.hide()不包含该术语的那些。这太慢了。

我发现一种更快的方法是遍历所有内容<li>并将类.hidden应用于所有需要隐藏的内容,然后在循环结束时执行$('.hidden').hide(). 不过,这感觉有点骇人听闻。

一种可能更快的方法可能是.hidden使用document.styleSheets. 谁能想到更好的方法?

编辑:让我澄清一些我不确定有多少人知道的事情。如果您在循环的每次迭代中更改 DOM,并且该更改会导致页面被重绘,那么这将比“准备”所有更改并在循环完成时立即应用它们要慢得多。

4

7 回答 7

24

每当您处理数千个项目时,DOM 操作都会很慢。循环遍历许多 DOM 元素并根据元素的特征来操作每个元素通常不是一个好主意,因为这涉及在每次迭代中对 DOM 方法的大量调用。如您所见,它真的很慢。

更好的方法是将数据与 DOM 分开。搜索 JS 字符串数组要快几个数量级。

这可能意味着将您的数据集加载为 JSON 对象。如果这不是一个选项,您可以遍历<li>s 一次(在页面加载时),并将数据复制到一个数组中。

现在您的数据集不依赖于存在的 DOM 元素,您可以在每次用户键入时简单地替换<ul>using的全部内容。.html()(这比 JS DOM 操作要快得多,因为浏览器可以优化 DOM 更改,只需更改innerHTML.)

var dataset = ['term 1', 'term 2', 'something else', ... ];

$('input').keyup(function() {
    var i, o = '', q = $(this).val();
    for (i = 0; i < dataset.length; i++) {
        if (dataset[i].indexOf(q) >= 0) o+='<li>' + dataset[i] + '</li>';
    }
    $('ul').html(o);
});

如您所见,这是非常快的。


但是请注意,如果您将其增加到 10,000 个项目,则在前几次击键时性能开始受到影响。这与插入到 DOM 中的结果数量有关,而不是与正在搜索的原始项目数量有关。(随着您键入的内容越多,要显示的结果越少,性能也很好——即使它仍在搜索所有 10,000 个项目。)

为避免这种情况,我会考虑将显示的结果数量限制在一个合理的范围内。(1,000 似乎和任何一个一样好。)这是自动完成;没有人真正查看所有结果——他们将继续输入,直到结果集可供人类管理。

于 2012-08-12T20:05:21.203 回答
2

我知道这是个老问题,但我对任何答案都不满意。目前我正在开发一个使用 jQuery Selectable 列表的 Youtube 项目,该列表包含大约 120.000 个项目。这些列表可以按文本过滤,然后显示相应的项目。隐藏所有不匹配元素的唯一可接受的方法是先隐藏 ul 元素,而不是隐藏 li 元素并再次显示 list(ul) 元素。

于 2015-09-14T09:43:12.130 回答
1

您可以直接选择所有 <li>,然后过滤它们:($("li").filter(function(){...}).hide()请参阅此处

(对不起,我之前发错了)

于 2012-08-12T19:44:53.193 回答
1

您可以使用 jQuery contains() 选择器来查找列表中具有特定文本的所有项目,然后将其隐藏,如下所示:

HTML:

 <ul id="myList">
      <li>this</li>
      <li>that</li>
 <ul>​

jQuery

var term = 'this';    
$('li:contains("' + term + '")').hide();​
于 2012-08-12T19:55:33.797 回答
1

您可以使用更独特的技术,在技术上不使用 JavaScript 来进行实际隐藏,方法是将数据副本放入属性中,并使用 CSS 属性选择器。

例如,如果术语是secret,并且您将数据的副本放在data-term属性中,则可以使用以下 CSS:

li[data-term*="secret"] {
    display: none;
}

要动态执行此操作,您必须在 javascript 中向头部添加样式:

function hideTerm(term) {
    css = 'li[data-term*="'+term+'"]{display:none;}'
    style = $('<style type="text/css">').text(css)
    $('head').append(style);
}

如果您要这样做,您需要确保在停止使用样式标签时清理它们。

这可能是最快的,因为 CSS 选择在现代浏览器中非常快。很难进行基准测试,所以我不能肯定地说。

于 2012-08-12T20:26:12.957 回答
0

怎么样:

<style>
    .hidden{ display: none; }
</style>

这样您就不必使用 $('.hidden').hide() 进行额外的查询?

于 2012-08-12T19:46:30.863 回答
0

无需重新定义样式表规则,您可以直接将“隐藏”类属性定义为“显示:无”;在您的页面之前,您可以在通过 javascript 验证条件后应用您定义的类,如下所示。

$("li").each(function(){if(condition){$(this).addClass('hide');}});

之后,如果你想再次显示那些 li,你可以像下面这样删除类

$("li").each(function(){if(condition){$(this).removeClass('hide');}});
于 2012-08-12T19:53:51.923 回答