【问题标题】:Fastest way to hide thousands of <li> elements?隐藏数千个 <li> 元素的最快方法?
【发布时间】:2012-08-09 03:38:50
【问题描述】:

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

我最初使用 jQuery 的 each 遍历所有 &lt;li&gt; 并将 .hide() 应用于不包含该术语的那些。这太慢了。

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

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

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

【问题讨论】:

  • 你能补充一下条件是什么,如果不是那么复杂,你可以使用css
  • 这有点奇怪,因为它应该更快地循环遍历项目并对要隐藏的项目执行 .hide() 而不是循环遍历,添加一个类,然后隐藏所有的与那个班级。所以你的实际代码搞砸了。您必须披露实际代码,以便我们提供准确的建议。此外,您需要在多个浏览器中使用 jsperf 之类的工具进行测试,以便在多个浏览器中得出准确的性能结论。
  • @jfriend00 问题可能源于调用$ 数千次。
  • 为什么需要hide() 所有.hidden 元素?那不应该已经在你的样式表中定义了吗?
  • 我要做的是优化搜索数据结构,搜索并从结果中动态创建元素,而不是一直操纵巨大的 dom 树。这样,您一次只能拥有 maxSearchResults 数量的 lis...

标签: javascript jquery optimization hide


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      这可能意味着将您的数据集加载为 JSON 对象。如果这不是一个选项,您可以循环一次&lt;li&gt;s(在页面加载时),然后将数据复制到一个数组中。

      现在您的数据集不依赖于存在的 DOM 元素,您可以在每次用户键入时使用 .html() 简单地替换 &lt;ul&gt; 的全部内容。 (这比 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);
      });
      

      As you can see,这个速度非常快。


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

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

      【讨论】:

      • 好的,这太棒了!我已经开始考虑这样的事情,但我不确定删除
          的内容并重新创建它们(一步)的时间是否比仅仅更改 CSS 规则(实际的 document.styleSheets.. ..) 已经存在。你确定是这样吗?
      • 是的。请参阅我刚刚添加的演示。
      【解决方案4】:

      不用重新定义 Stylesheets 规则,你可以直接定义 'hide' 类属性为“显示:无;”在您的页面之前,您可以 通过javascript验证条件后应用您定义的类, 如下所示。

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

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

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

      【讨论】:

        【解决方案5】:

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

        HTML:

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

        jQuery

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

        【讨论】:

          【解决方案6】:

          怎么样:

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

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

          【讨论】:

          • "display : none" 导致 dom 回流。而且会很慢。更好的选择是“可见性:隐藏”
          【解决方案7】:

          您可以直接选择所有

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

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

        • 【讨论】:

          • @MilanJaric:如果我理解正确,OP 的原始方法是使用each() 遍历所有&lt;li&gt; 标签,并将hide() 应用于每个标签。这个答案的建议是将它们全部过滤到一个 JQuery 集合中,然后将hide() 应用于所有这些集合。这样,hide() 只会被调用一次
          猜你喜欢
          • 1970-01-01
          • 2011-07-15
          • 2022-07-27
          • 2011-09-17
          • 1970-01-01
          • 2017-05-12
          • 1970-01-01
          • 2015-11-24
          • 1970-01-01
          相关资源
          最近更新 更多