javascript - html 表卡住列与纯 javascript,小 CSS

标签 javascript html css datatable html-table

我正在尝试实现将 html 水平滚动表的左侧三列设置为“卡住”或“固定”。我已经仔细查看了网络上的所有解决方案,但我有很多要求,因此无法找到解决方案:

  1. 尽可能少地更改 CSS,因为此表已经应用了大量 CSS。此表与 jQuery DataTables 具有许多相同的功能所以发生了很多事情。
  2. 我愿意根据需要做尽可能多的 Javascript,但它需要是纯 JS,不能像 jQuery 那样。
  3. 无法复制表格(我见过将表格的一个副本放在另一个副本之上的解决方案)。
  4. 表格必须保持全白,我无法为卡住的列分配背景色作为“修复”以在卡住的列滚动到其他列时隐藏它们。

你们对如何使用 Javascript 实现该功能有什么建议吗?似乎大多数适用于现有表格(并且不在表格中包含此功能)的实现都依赖于更改大量 CSS。即使只是关于如何在 javascript 中开始使用它的一些建议也会有所帮助。我认为如果我利用滚动方面应该有一种方法,但我不确定。

最佳答案

我使用了一个 fixed-table.js 库来实现没有 jquery 的解决方案。试试下面的片段。

var fixedTable = fixTable(document.getElementById('fixed-table-container-demo'));

function fixTable(container) {
  // Store references to table elements
  var thead = container.querySelector('thead');
  var tbody = container.querySelector('tbody');

  // Style container
  container.style.overflow = 'auto';
  container.style.position = 'relative';

  // Add inline styles to fix the header row and leftmost column
  function relayout() {
    var ths = [].slice.call(thead.querySelectorAll('th'));
    var tbodyTrs = [].slice.call(tbody.querySelectorAll('tr'));

    /**
     * Remove inline styles so we resort to the default table layout algorithm
     * For thead, th, and td elements, don't remove the 'transform' styles applied
     * by the scroll event listener
     */
    tbody.setAttribute('style', '');
    thead.style.width = '';
    thead.style.position = '';
    thead.style.top = '';
    thead.style.left = '';
    thead.style.zIndex = '';
    ths.forEach(function(th) {
      th.style.display = '';
      th.style.width = '';
      th.style.position = '';
      th.style.top = '';
      th.style.left = '';
    });
    tbodyTrs.forEach(function(tr) {
      tr.setAttribute('style', '');
    });
    [].slice.call(tbody.querySelectorAll('td'))
      .forEach(function(td) {
        td.style.width = '';
        td.style.position = '';
        td.style.left = '';
      });

    /**
     * Store width and height of each th
     * getBoundingClientRect()'s dimensions include paddings and borders
     */
    var thStyles = ths.map(function(th) {
      var rect = th.getBoundingClientRect();
      var style = document.defaultView.getComputedStyle(th, '');
      return {
        boundingWidth: rect.width,
        boundingHeight: rect.height,
        width: parseInt(style.width, 10),
        paddingLeft: parseInt(style.paddingLeft, 10)
      };
    });

    // Set widths of thead and tbody
    var totalWidth = thStyles.reduce(function(sum, cur) {
      return sum + cur.boundingWidth;
    }, 0);
    tbody.style.display = 'block';
    tbody.style.width = totalWidth + 'px';
    thead.style.width = totalWidth - thStyles[0].boundingWidth + 'px';

    // Position thead
    thead.style.position = 'absolute';
    thead.style.top = '0';
    thead.style.left = thStyles[0].boundingWidth + 'px';
    thead.style.zIndex = 10;

    // Set widths of the th elements in thead. For the fixed th, set its position
    ths.forEach(function(th, i) {
      th.style.width = thStyles[i].width + 'px';
      if (i === 0) {
        th.style.position = 'absolute';
        th.style.top = '0';
        th.style.left = -thStyles[0].boundingWidth + 'px';
      }
    });

    // Set margin-top for tbody - the fixed header is displayed in this margin
    tbody.style.marginTop = thStyles[0].boundingHeight + 'px';

    // Set widths of the td elements in tbody. For the fixed td, set its position
    tbodyTrs.forEach(function(tr, i) {
      tr.style.display = 'block';
      tr.style.paddingLeft = thStyles[0].boundingWidth + 'px';
      [].slice.call(tr.querySelectorAll('td'))
        .forEach(function(td, j) {
          td.style.width = thStyles[j].width + 'px';
          if (j === 0) {
            td.style.position = 'absolute';
            td.style.left = '0';
          }
        });
    });
  }

  // Initialize table styles
  relayout();

  // Update table cell dimensions on resize
  window.addEventListener('resize', resizeThrottler, false);
  var resizeTimeout;

  function resizeThrottler() {
    if (!resizeTimeout) {
      resizeTimeout = setTimeout(function() {
        resizeTimeout = null;
        relayout();
      }, 500);
    }
  }

  // Fix thead and first column on scroll
  container.addEventListener('scroll', function() {
    thead.style.transform = 'translate3d(0,' + this.scrollTop + 'px,0)';
    var hTransform = 'translate3d(' + this.scrollLeft + 'px,0,0)';
    thead.querySelector('th').style.transform = hTransform;
    [].slice.call(tbody.querySelectorAll('tr > td:first-child'))
      .forEach(function(td, i) {
        td.style.transform = hTransform;
      });
  });

  /**
   * Return an object that exposes the relayout function so that we can
   * update the table when the number of columns or the content inside columns changes
   */
  return {
    relayout: relayout
  };
}
.fixed-table-container {
  height: 300px;
  box-sizing: border-box;
  border: 1px solid #ccc;
  margin-bottom: 40px;
}

.fixed-table-container table {
  border-collapse: collapse;
  width: 100%;
}

.fixed-table-container th,
.fixed-table-container td {
  border-right: 1px solid #ccc;
  border-bottom: 1px solid #ccc;
  padding: 8px;
  text-align: left;
  vertical-align: top;
  /**
    * Current implementation doesn't work when
    * cells in a row have different heights
    */
  white-space: nowrap !important;
}

.fixed-table-container th {
  background: #fff;
  font-size: 12px;
  line-height: 16px;
  padding-top: 10px;
  padding-bottom: 10px;
}

.fixed-table-container td:first-child {
  background: #fff;
}

.fixed-table-container tr:last-child td {
  border-bottom: 0;
}

.fixed-table-container th:last-child,
.fixed-table-container td:last-child {
  border-right: 0;
}
<div id="fixed-table-container-demo" class="fixed-table-container">
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Status</th>
        <th>Description</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Lorem</td>
        <td>Lorem ipsum</td>
        <td>Lorem</td>
      </tr>
      <tr>
        <td>Lorem ipsum dolor sit amet</td>
        <td>Lorem</td>
        <td>Dolor</td>
      </tr>
      <tr>
        <td>Lorem ipsum dolor</td>
        <td>sit</td>
        <td>Lorem ipsum dolor sit amet ipsum dolor sit amet</td>
      </tr>
      <tr>
        <td>Lorem</td>
        <td>Lorem ipsum</td>
        <td>Lorem ipsum dolor sit amet</td>
      </tr>
      <tr>
        <td>Dolor sit amet</td>
        <td>Dolor sit amet</td>
        <td>Lorem</td>
      </tr>
      <tr>
        <td>Lorem ipsum dolor</td>
        <td>Lorem ipsum dolor sit amet ipsum dolor sit amet</td>
        <td>Sit amet</td>
      </tr>
      <tr>
        <td>Lorem</td>
        <td>Lorem ipsum</td>
        <td>Lorem</td>
      </tr>
      <tr>
        <td>Lorem ipsum dolor sit amet</td>
        <td>Lorem</td>
        <td>Dolor</td>
      </tr>
      <tr>
        <td>Lorem ipsum dolor</td>
        <td>sit</td>
        <td>Lorem ipsum dolor sit amet</td>
      </tr>
      <tr>
        <td>Lorem</td>
        <td>Lorem ipsum</td>
        <td>Lorem dolor sit amet</td>
      </tr>
      <tr>
        <td>Dolor sit amet</td>
        <td>Dolor sit amet</td>
        <td>Lorem</td>
      </tr>
      <tr>
        <td>Lorem ipsum dolor</td>
        <td>Lorem ipsum dolor sit</td>
        <td>Sit amet lorem</td>
      </tr>
    </tbody>
  </table>
</div>

关于javascript - html 表卡住列与纯 javascript,小 CSS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48593384/

相关文章:

javascript - 在服务器 Onclick 事件之后调用 Javascript 函数

javascript - 谷歌浏览器在隐藏元素时破坏了 HTML 布局

javascript - 将 HTML 代码更改为 json_encode

html - 如何将我的单栏博客内容设置为 "zoom"以填充移动浏览器的宽度?

javascript - 无法在页面刷新时获取元素宽度

javascript - Persistence.js 在两个方向上添加多对多

javascript - 将文本插入到不确定数量的跨度中,For Loop Javascript

html - 是否可以使带内联 block 的 DIV 的行为与带 align=left 的 IMG 完全一样?

html - 在 Drupal 中使页面内容全宽。

html - p 和 div 标签内标题的差异结果