插件窝 干货文章 原生JS如何实现Excel式表格的精确行列滚动?

原生JS如何实现Excel式表格的精确行列滚动?

contentContainer 滚动 headerContainer excelContainer 243    来源:    2025-03-26

原生JS实现Excel式表格精确行列滚动方案

要实现类似Excel的精确行列滚动效果,需要考虑以下几个关键点:

核心实现思路

  1. 双重滚动容器结构

    • 外层容器处理整体滚动
    • 内层容器处理内容区域
    • 固定行列使用绝对定位
  2. 同步滚动机制

    • 监听滚动事件并同步相关区域的滚动位置
    • 使用scrollLeftscrollTop控制精确滚动

代码实现示例

<div class="excel-container" id="excelContainer">
  <!-- 固定表头 -->
  <div class="header-container" id="headerContainer">
    <table class="header-table">
      <!-- 表头内容 -->
    </table>
  </div>

  <!-- 固定左侧列 -->
  <div class="left-container" id="leftContainer">
    <table class="left-table">
      <!-- 左侧列内容 -->
    </table>
  </div>

  <!-- 主内容区域 -->
  <div class="content-container" id="contentContainer">
    <table class="content-table" id="contentTable">
      <!-- 表格内容 -->
    </table>
  </div>
</div>
.excel-container {
  position: relative;
  width: 800px;
  height: 600px;
  overflow: auto;
}

.header-container {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  overflow: hidden;
}

.left-container {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  overflow: hidden;
}

.content-container {
  position: absolute;
  top: 0;
  left: 0;
  overflow: auto;
}
// 获取DOM元素
const excelContainer = document.getElementById('excelContainer');
const headerContainer = document.getElementById('headerContainer');
const leftContainer = document.getElementById('leftContainer');
const contentContainer = document.getElementById('contentContainer');
const contentTable = document.getElementById('contentTable');

// 设置初始尺寸
function setDimensions() {
  const headerHeight = headerContainer.offsetHeight;
  const leftWidth = leftContainer.offsetWidth;

  contentContainer.style.top = `${headerHeight}px`;
  contentContainer.style.left = `${leftWidth}px`;
  contentContainer.style.width = `${excelContainer.offsetWidth - leftWidth}px`;
  contentContainer.style.height = `${excelContainer.offsetHeight - headerHeight}px`;

  headerContainer.style.width = `${excelContainer.offsetWidth - leftWidth}px`;
  leftContainer.style.height = `${excelContainer.offsetHeight - headerHeight}px`;
}

// 同步滚动
contentContainer.addEventListener('scroll', function() {
  headerContainer.scrollLeft = contentContainer.scrollLeft;
  leftContainer.scrollTop = contentContainer.scrollTop;
});

// 窗口大小变化时重新计算
window.addEventListener('resize', setDimensions);

// 初始化
setDimensions();

高级优化方案

  1. 虚拟滚动(处理大数据量):

    function renderVisibleRows() {
     const rowHeight = 30; // 假设每行高度
     const startRow = Math.floor(contentContainer.scrollTop / rowHeight);
     const visibleRowCount = Math.ceil(contentContainer.clientHeight / rowHeight);
    
     // 只渲染可见行
     // ...
    }
    
  2. 性能优化

    // 使用requestAnimationFrame优化滚动性能
    let isScrolling = false;
    contentContainer.addEventListener('scroll', function() {
     if (!isScrolling) {
       window.requestAnimationFrame(function() {
         headerContainer.scrollLeft = contentContainer.scrollLeft;
         leftContainer.scrollTop = contentContainer.scrollTop;
         isScrolling = false;
       });
       isScrolling = true;
     }
    });
    
  3. 精确像素级滚动

    // 确保行高和列宽是整数像素
    function normalizeCellSizes() {
     const rows = contentTable.rows;
     for (let i = 0; i < rows.length; i++) {
       rows[i].style.height = `${Math.floor(rows[i].offsetHeight)}px`;
     }
     // 同样处理列宽...
    }
    

注意事项

  1. 浏览器兼容性:不同浏览器对滚动事件的处理可能有差异
  2. 性能考量:大数据量时考虑虚拟滚动技术
  3. 触摸设备:需要额外处理触摸事件以实现平滑滚动
  4. 滚动条样式:可以自定义滚动条以获得更好的用户体验

这种实现方式可以创建类似Excel的精确行列滚动效果,同时保持较好的性能表现。