javascript - jQuery:在滚动时修复表行 - 性能问题

标签 javascript jquery css performance scroll

我有一个包含不同类别的表格。每个类别都有一个标题,我希望在滚动时将该标题的位置固定在表格的顶部。

简单示例:如果我看到 table 上有汽车,我希望 thead 说“Cars”。如果我继续滚动并开始看到摩托车,我希望它显示“摩托车”。

这是我的代码的简化版本的片段,用于表示上面的示例:

//start scrolling
$('tbody').scroll(function() {
  doStuff();
});

function doStuff() {

  $('.title').each(function() {

    //Set vars
    var $this = $(this);
    var childPos = $this.position();
    var parentPos = $('tbody').position();
    var currentTop = childPos.top - parentPos.top;

    //Listener
    if (currentTop <= 0) {
      $this.addClass('active')
      $('thead').find('.active').remove();
      $('.active').last().clone().appendTo($('thead'));
    } else {
      $this.removeClass('active');

    }
  });


}
.table-wrapper {
  height: 180px;
  overflow: hidden;
}
table {
  font: arial;
  text-align: left;
  width: 300px;
}
tbody {
  display: block;
  height: 80px;
  overflow: auto;
  width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th colspan="2">Vehicles</th>
      </tr>
    </thead>

    <tbody>
      <tr>
        <th colspan="2" class="title">Cars</th>
      </tr>
      <tr>
        <td>Opel</td>
        <td>Corsa</td>
      </tr>
      <tr>
        <td>Renault</td>
        <td>Clio</td>
      </tr>
      <tr>
        <td>Citroen</td>
        <td>AX</td>
      </tr>

      <tr>
        <th colspan="2" class="title">Motorbikes</th>
      </tr>
      <tr>
        <td>Honda</td>
        <td>Hornet</td>
      </tr>
      <tr>
        <td>Yamaha</td>
        <td>Virago</td>
      </tr>
      <tr>
        <td>Suzuki</td>
        <td>GSXR</td>
      </tr>

      <tr>
        <th colspan="2" class="title">Planes</th>
      </tr>
      <tr>
        <td>Boeing</td>
        <td>737</td>
      </tr>
      <tr>
        <td>Boeing</td>
        <td>767</td>
      </tr>
      <tr>
        <td>Boeing</td>
        <td>777</td>
      </tr>
    </tbody>
  </table>
</div>

此外,here's a jsfiddle .

当以这种方式做事时,每次滚动移动时我都会调用我的整个函数,所以正如我所预料的那样性能很差。

如何优化我的代码以使用滚动条运行?我见过的所有解决方案都适用于 setTimeout,但我不想在 250 毫秒不滚动后才运行我的函数,因为用户可能会滚动一段时间并且 thead 将不正确。

请记住,我的表中可以有数千行。谢谢。

最佳答案

如果您不想设置超时来延迟 .scroll() 调用,您的选择仅限于优化您的 .scroll() 事件尽可能快。

我在这里写了一个替代方法,但我没有在大表上测试过它:https://jsfiddle.net/sduknuzw/69/

您会注意到我将所有昂贵的计算都移到了循环之外,并在初始加载时处理它们。这让我可以简单地处理 .scroll() 事件并只处理一次昂贵的计算。

//initialize headers
var headers = [];
$('.title').each(function(index) {
  var header = {
    thead: $(this),
    top: $(this).parent().index() * $(this).outerHeight(),
    bottom: 0
  };
  headers.push(header);
});

//calculate header container heights
for (var i = 0; i < headers.length; ++i) {
    headers[i].bottom = (i+1 < headers.length) ? headers[i+1].top : 100000;
}

在上面的 header 代码中,我构建了一个 header 对象,其中顶部/底部是一个假想容器的位置值。稍后使用此容器来找出滚动条在哪个部分。

我会认为这部分代码有点老套。我不喜欢使用 CSS 值进行计算,因为它们在不同浏览器中并不总是相同的。此外,此代码不适应具有不同高度的行/标题,因此如果不根据您的需要对其进行修改,它可能无法工作。但它的效果足以证明我正在努力实现的目标。

为了更好地理解数学和我想要完成的事情,想象一下这个简化的场景:

<style>
    table tr td {
        height:20px
    }
</style

<table>
    <tbody>
      <tr><th colspan="2" class="title">Cars</th></tr> //Row index 0
      <tr><td>1</td></tr>
      <tr><th colspan="2" class="title">Motorbikes</th></tr> //Row index 2
      <tr><td>2</td></tr>
      <tr><td>3</td></tr>
      <tr><th colspan="2" class="title">Planes</th></tr> //Row index 5
      <tr><td>4</td></tr>
  </tbody>
</table>

“top”值是行索引乘以每行的高度。 “底部”值基本上只是下一个 header 的“顶部”值。

对于我们的小示例, header 容器值将是这样的:

Car { 
    top: 0, 
    bottom: 40 
}
Motorbikes { 
    top: 40,    // Row Index * Row Height
    bottom: 100 // Next Headers Top
}
Planes {
    top: 100, 
    bottom: 140
}

从视觉上看,它看起来像这样:

-------------------  top: 0
|  th   |   Cars   |
|  td   |    1     |
-------------------  top/bottom: 40
|  th   |  Motors  |
|  td   |    2     |
|  td   |    3     |
-------------------  top/bottom: 100
|  th   |  Planes  |
|  td   |    4     |
-------------------  bottom: 140

代码的最后一部分是 scroll 循环本身。由于我在上面所做的额外工作,我们不必遍历每个滚动条上的所有 .title 对象。该解决方案将开销减少为几个应该相对便宜的数值比较。

var headerIndex = 0;
function doStuff() {
    var scroll = $('tbody').scrollTop();
    if (scroll >= headers[headerIndex].top && scroll < headers[headerIndex].bottom) {
        return true;
    }
    else {
        //get new headerindex and update header
        headers[headerIndex].thead.removeClass('active');
        headerIndex = (scroll < headers[headerIndex].top) ? headerIndex-1 : headerIndex+1;
        headers[headerIndex].thead.addClass('active');

        $('thead').find('.active').remove();
        $('.active').last().clone().appendTo($('thead'));
    }
}

它的代码比你拥有的要多得多,并且有一定的改进空间,但我会尝试这样的事情,看看你是否看到任何明显的性能提升。

关于javascript - jQuery:在滚动时修复表行 - 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36775523/

相关文章:

javascript - 使用 Node.js 进行回调和返回

javascript - 编辑 HTML 表格单元格

javascript - 将动态生成的文本框值传递给 ASP.NET MVC 中的 Controller

javascript - 尝试使用 JSON 获取级联 DDL 但未得到响应

html - 响应式导航不起作用

javascript - Jquery/Ajax 模式未加载

javascript - 使用 jQuery 解析已经过时的 HTML

jquery - 为什么 jquery 在 .load() 之后看不到页面的变化?

css 容器 div 未与页面顶部对齐

css - 防止预加载图像?