隐藏数千个<li>元素的最快方法

Fastest way to hide thousands of <li> elements?

本文关键字:li 元素 方法 千个 隐藏      更新时间:2023-09-26

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

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

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

一种可能更快的方法可能是使用 document.styleSheets 重写 .hidden 类的 CSS 规则。 谁能想到更好的方法?

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

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

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

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

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

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 似乎和任何一样好。 这是自动完成的;没有人真正查看所有结果 - 他们会继续键入,直到结果集对人类来说是可管理的。

我知道

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

您可以直接选择所有

  • 然后过滤它们: $("li").filter(function(){...}).hide()(见这里)

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

  • 您可以使用 jQuery contains() 选择器在包含特定文本的列表中查找所有项目,然后隐藏它们,如下所示:

    .HTML:

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

    jQuery

    var term = 'this';    
    $('li:contains("' + term + '")').hide();​
    

    您可以使用一种更独特的技术,该技术在技术上不使用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选择在现代浏览器中非常快。这很难进行基准测试,所以我不能肯定地说。

    怎么样:

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

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

    无需重新定义样式表规则,您可以直接定义"隐藏"类属性到"显示:无;"之前和你的页面中,你可以只应用通过 JavaScript 验证条件后定义的类,如下。

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

    稍后,如果您想再次显示这些 li,您可以像下面这样删除该类

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