插件窝 干货文章 原生JS如何实现表格滚动吸附,精确控制行列显示隐藏?

原生JS如何实现表格滚动吸附,精确控制行列显示隐藏?

const table rows Scroll 964    来源:    2025-03-26

原生JS实现表格滚动吸附与行列控制

表格滚动吸附实现

滚动吸附(Scroll Snap)可以让表格在滚动时自动对齐到行或列的边界,提供更好的用户体验。以下是原生JS实现方案:

1. 使用CSS Scroll Snap

.scroll-container {
  overflow: auto;
  scroll-snap-type: y mandatory; /* 垂直方向吸附 */
  height: 300px; /* 固定高度 */
}

.scroll-item {
  scroll-snap-align: start; /* 吸附到起始位置 */
}

2. JS辅助实现更精确控制

const table = document.querySelector('.scroll-container');
let isScrolling = false;

table.addEventListener('scroll', () => {
  if (!isScrolling) {
    window.requestAnimationFrame(() => {
      const rowHeight = 40; // 每行高度
      const snapPosition = Math.round(table.scrollTop / rowHeight) * rowHeight;
      table.scrollTop = snapPosition;
      isScrolling = false;
    });
    isScrolling = true;
  }
});

精确控制行列显示隐藏

1. 列显示隐藏控制

function toggleColumn(columnIndex, show) {
  const table = document.getElementById('myTable');
  const rows = table.rows;

  for (let i = 0; i < rows.length; i++) {
    const cell = rows[i].cells[columnIndex];
    cell.style.display = show ? '' : 'none';
  }
}

// 隐藏第2列(索引从0开始)
toggleColumn(1, false);

2. 行显示隐藏控制

function toggleRow(rowIndex, show) {
  const table = document.getElementById('myTable');
  const row = table.rows[rowIndex];
  row.style.display = show ? '' : 'none';
}

// 隐藏第3行
toggleRow(2, false);

3. 基于条件的行列控制

function filterRows(columnIndex, filterValue) {
  const table = document.getElementById('myTable');
  const rows = table.rows;

  for (let i = 1; i < rows.length; i++) { // 从1开始跳过表头
    const cell = rows[i].cells[columnIndex];
    const match = cell.textContent.includes(filterValue);
    rows[i].style.display = match ? '' : 'none';
  }
}

// 只显示"状态"列包含"完成"的行
filterRows(3, "完成");

完整示例

<!DOCTYPE html>
<html>
<head>
  <style>
    .table-container {
      width: 100%;
      overflow: auto;
      height: 300px;
      scroll-snap-type: y mandatory;
    }

    table {
      width: 100%;
      border-collapse: collapse;
    }

    th, td {
      border: 1px solid #ddd;
      padding: 8px;
      text-align: left;
      scroll-snap-align: start;
    }

    th {
      background-color: #f2f2f2;
      position: sticky;
      top: 0;
    }

    .controls {
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div class="controls">
    <button onclick="toggleColumn(1, false)">隐藏第二列</button>
    <button onclick="toggleColumn(1, true)">显示第二列</button>
    <button onclick="filterRows(2, '完成')">只显示完成项</button>
  </div>

  <div class="table-container" id="tableContainer">
    <table id="myTable">
      <thead>
        <tr>
          <th>ID</th>
          <th>名称</th>
          <th>状态</th>
          <th>日期</th>
        </tr>
      </thead>
      <tbody>
        <tr><td>1</td><td>项目A</td><td>进行中</td><td>2023-01-01</td></tr>
        <tr><td>2</td><td>项目B</td><td>完成</td><td>2023-01-02</td></tr>
        <!-- 更多行... -->
      </tbody>
    </table>
  </div>

  <script>
    // 滚动吸附增强
    const container = document.getElementById('tableContainer');
    let isScrolling = false;

    container.addEventListener('scroll', () => {
      if (!isScrolling) {
        window.requestAnimationFrame(() => {
          const rowHeight = 40; // 根据实际行高调整
          const snapPosition = Math.round(container.scrollTop / rowHeight) * rowHeight;
          container.scrollTop = snapPosition;
          isScrolling = false;
        });
        isScrolling = true;
      }
    });

    // 列显示/隐藏
    function toggleColumn(columnIndex, show) {
      const table = document.getElementById('myTable');
      const rows = table.rows;

      for (let i = 0; i < rows.length; i++) {
        const cell = rows[i].cells[columnIndex];
        if (cell) cell.style.display = show ? '' : 'none';
      }
    }

    // 行过滤
    function filterRows(columnIndex, filterValue) {
      const table = document.getElementById('myTable');
      const rows = table.rows;

      for (let i = 1; i < rows.length; i++) {
        const cell = rows[i].cells[columnIndex];
        const match = cell.textContent.includes(filterValue);
        rows[i].style.display = match ? '' : 'none';
      }
    }
  </script>
</body>
</html>

性能优化建议

  1. 对于大型表格,使用虚拟滚动技术,只渲染可见区域的行
  2. 使用requestAnimationFrame优化滚动性能
  3. 考虑使用Intersection Observer API来检测元素可见性
  4. 对于频繁的显示/隐藏操作,可以先将表格移出DOM,完成操作后再添加回去

这些原生JS实现方案可以根据具体需求进行调整和扩展。