草庐IT

javascript - 转换/移动大量 DOM 元素的最高效方式

coder 2023-08-04 原文

前段时间我为 AngularJS(使用 Angular Material)构建了一个树形表结构。

我的目标是让它只在大屏幕(1280 和更高)上运行,但现在我想更新它并让它在较小的设备(主要是平板电脑)上运行而不限制数据。由于性能原因,我希望 HTML 尽可能简单(树形表可以有 1000 多行,因此为单行创建更复杂的 HTML 将延长追加和呈现表行所需的时间(行是动态的,所以它不仅仅是关于初始渲染))。

我想出了一个想法,即我将保留第一个包含名称的单元格的“固定”部分,并滚动包含所有指标并将同步滚动的第二部分。

当前单行HTML:

<div class="tb-header layout-row">
  <div class="tb-title"><span>Name</span></div>
  <div class="tb-metrics">
     <div class="layout-row">
        <div class="tb-cell flex-10">812</div>
        <div class="tb-cell flex-7">621</div>
        <div class="tb-cell flex-4">76.5</div>
        <div class="tb-cell flex-7">289</div>
        <div class="tb-cell flex-4">46.5</div>
        <div class="tb-cell flex-7">308</div>
        <div class="tb-cell flex-4">49.6</div>
        <div class="tb-cell flex-7">390</div>
        <div class="tb-cell flex-4">48.0</div>
        <div class="tb-cell flex-7">190</div>
        <div class="tb-cell flex-4">23.4</div>
        <div class="tb-cell flex-7">0</div>
        <div class="tb-cell flex-4">0.0</div>
        <div class="tb-cell flex-8">6.4</div>
        <div class="tb-cell flex-8">0.0</div>
        <div class="tb-cell flex-8"></div>
     </div>
  </div>

我的想法是使用 touchmove父容器上的事件(包装整个树并绑定(bind)为指令)并检查何时 touchmove从指标部分开始,然后计算我应该移动指标的值。那部分工作正常。 当我想在 .tb-metrics > 上应用偏移量时,问题就开始了.

我的第一次尝试是使用 jQuery:

function moveMetrics( offset ) {
  var ofx = offset < 0 ? (offset < -getMetricsScrollWidth() ? -getMetricsScrollWidth() : offset) : 0;
  $('.tb-metrics').children().css('transform', 'translateX(' + ofx + 'px)');

  /*...*/

}

不幸的是,当表包含更多行时,此解决方案非常慢(我无法缓存行,因为它们是动态的)。

在我的第二次尝试中,我尝试尽可能避免 DOM 操作。 为此,我决定添加 <script>包含适用于 .metrics > .layout-row 的 css 的 dom 标记.

解决方法:

function moveMetrics( offset ) {
  var ofx = offset < 0 ? (offset < -getMetricsScrollWidth() ? -getMetricsScrollWidth() : offset) : 0
    , style = $( '#tbMetricsVirtualScroll' )
    ;

  if ( !style.length ) {
    body.append( '<style id="tbMetricsVirtualScroll">.tb-metrics > * {transform: translateX(' + ofx + 'px)}</style>' );
    style = $( '#tbMetricsVirtualScroll' );
  } else {
    style.text( '.tb-metrics > * {transform: translateX(' + ofx + 'px)}' );
  }
  /*...*/
}

但是,当表包含大量行时,它似乎并没有快多少。所以这不是 DOM 操作,而是渲染/绘画 View 似乎是这里的瓶颈。

我试图创建某种虚拟滚动,但是因为树结构对于不同的数据集是不同的并且可以具有“无限”数量的级别(每行可以包含新的 ng-repeat 中的子行)这真的很难任务。

如果有任何关于如何在不使用虚拟滚动条的情况下提高性能的想法,我将不胜感激。

编辑:

Chrome时间轴截图显示滚动的大部分时间都花在了渲染上(我猜是因为复杂的DOM结构)

编辑 2:

我不会说我实现了绝对流畅的滚动,但我发现了一些可以显着提高性能的东西(其中一些并不明显,经过如此小的更改后结果比我预期的要好)。

  • 简化类选择器: .tb-header > .tb-metrics > .tb-cell.tb-specific-cell 慢得多(似乎解析更复杂的选择器需要更多的时间?)
  • 从转换后的元素中移除不透明度和框阴影
  • 尝试将转换后的元素分布到新层(使用 css will-change 和/或 translateZ(0))

最佳答案

我过去在使用非常大的表时遇到过类似的问题。因此,将 UX 方面的事情排除在等式之外 - 为了实现您的目标可能是以下内容。与其保持第一张 table 固定并移动其余所有 table ,也许您可​​以尝试相反的方法。也就是,将表格放在溢出的容器中以允许水平滚动,并在垂直滚动时使用 translateY 移动第一列表格单元格。

按照我描述的方式,您可以检索第一个表格单元格的最大宽度(或者更好的是,设置一个固定宽度),绝对将每个单元格放在左侧 - 不过要小心,相关容器应该在溢出的表格,在每行的第二个表格单元格上设置一个 padding-left,等于第一个表格单元格,然后,当垂直滚动时,添加一个负的 translateY 值。然后选择器应该很容易访问“.layout-row .table-cell:first-child”。

同样对于较小的优化,请尝试使用 .attr('style', value) 而不是使用 .css()。另外,我读到你有动态内容并且不能缓存它,但是,也许你应该考虑在每次操作 DOM 时缓存一次。缓存的选定元素仍然比在每个滚动/触摸移动事件中计算选择器要好。

最后但同样重要的是,您还可以添加某种去抖动技术,这样滚动就不会在每个滚动帧上发生,但可能每 10 帧发生一次 - 它仍然对眼睛不可见,或者在任何情况下都比使用所有这些重绘事件使浏览器成为瓶颈。

关于javascript - 转换/移动大量 DOM 元素的最高效方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36129133/

有关javascript - 转换/移动大量 DOM 元素的最高效方式的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  6. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  7. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  8. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  9. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  10. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

随机推荐