我之前为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
事件(将整个树包装并绑定为指令),并检查当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操作。
为了实现这一点,我决定向dom添加<script>
标签,其中包含应用于.metrics > .layout-row
的css。
解决方案:
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操作,而是呈现/绘制视图。
我试图创建一种虚拟滚动的方式,但由于不同数据集的树结构不同,并且可以拥有“无限”级别(每行可以包含新的子行),这是一项非常困难的任务。
我会欣赏任何关于如何在不使用虚拟滚动的情况下改善性能的想法。
编辑:
Chrome时间线的截图显示,滚动的大部分时间都被渲染占用了(我猜这是因为复杂的DOM结构)。
第二次编辑:
我不会说我实现了完全流畅的滚动,但我找到了一些显着提高性能的方法(其中一些并不明显,还超出了我的期望)。
- 简化类选择器:
.tb-header > .tb-metrics > .tb-cell
比.tb-specific-cell
慢得多(似乎需要更长的时间来解析更复杂的选择器?) - 从变换元素中删除不透明度和框影
- 尝试将变换元素分配到新图层中(使用CSS
will-change
和/或translateZ(0)
)
overflow: auto
属性的容器。对于一个独立的容器来说,要完全实现平滑滚动是很困难的。这是否适用于您的情况?您是滚动整个文档还是一个独立的容器? - Andrew Sklyarevsky