LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

使用 HTML + JavaScript 实现表格滚动效果(附完整代码)

admin
2026年1月10日 9:33 本文热度 407
数据可视化中的动态展示能够有效吸引用户注意力,特别是在监控大屏或排行榜场景中。当数据量较大而显示区域有限时,滚动展示成为一种高效的解决方案。通过平滑的滚动动画,可以让用户在不中断观看的情况下浏览全部数据,提升信息获取效率。本文将介绍如何使用 HTML、CSS 和 JavaScript 实现表格滚动效果。

效果演示

这个表格滚动效果模拟了一个商品销售排行榜的展示界面。页面顶部显示表格标题,下方是带有表头的滚动表格区域。数据行会从底部向上滚动,当一行完全滚出视窗后,其后续行继续滚动。整个滚动过程平滑连续,当所有数据都滚动完成后,会立即回到初始状态。

页面结构

页面主要包括以下几个区域:

容器区域

包含整个表格组件的外层容器,设置了深色背景和合适的尺寸。
<div class="screen-container">  <div class="table-title">商品销售排行榜</div>  <div class="table-wrapper">    <!-- 表格内容 -->  </div>  <div class="control-btn">    <button id="pauseBtn">暂停滚动</button>    <button id="playBtn" disabled>继续滚动</button>  </div></div>

表头区域

固定不动的表格头部,包含列标题,不会随数据滚动。
<div class="table-header">  <table class="header-table">    <tr>      <th>序号</th>      <th>产品名称</th>      <th>数值</th>      <th>增长率</th>    </tr>  </table></div>

滚动表格区域

包含实际数据内容,是滚动效果的主要部分。
<div class="scroll-table" id="scrollTable">  <div class="table-content" id="tableContent"></div></div>

核心功能实现

数据初始化与渲染

首先准备表格数据,并根据容器高度计算最大可见行数。initTable 函数负责初始化表格内容,它复制原始数据以创建循环效果,并计算可显示的最大行数。当数据量少于最大可见行数时,自动禁用滚动功能。
function initTable() {  renderDataTable([...tableData, ...tableData]);
  const availableHeight = scrollTable.clientHeight;  maxVisibleRows = Math.floor(availableHeight / rowHeight);
  if (tableData.length <= maxVisibleRows) {    pauseBtn.disabled = true;    playBtn.disabled = true;    pauseBtn.textContent = '数据不足';    return false;  }
  return true;}

动态内容渲染

renderDataTable 函数根据传入的数据动态生成表格 HTML 内容。该函数不仅渲染基本的表格结构,还根据增长率的正负值设置不同的颜色样式,使数据展示更加直观。
function renderDataTable(data) {  const tableHtml = `<table class="data-table">      ${data.map(item => `<tr>          <td>${item.id}</td>          <td>${item.name}</td>          <td>${item.value}</td>          <td style="color: ${item.rate.includes('-') ? '#f56c6c' : '#67c23a'}">${item.rate}</td>        </tr>`).join('')}    </table>`;  tableContent.innerHTML = tableHtml;}

滚动动画控制

animateScroll 函数是滚动效果的核心,通过 requestAnimationFrame 实现平滑动画,并在每行到达顶部时设置暂停状态。
function animateScroll() {  if (!isScrolling) return;
  if (scrollState === 'scrolling') {    const distance = targetTop - topValue;
    if (Math.abs(distance) <= scrollSpeed) {      topValue = targetTop;      tableContent.style.top = `${topValue}px`;
      if (currentRowIndex >= tableData.length) {        topValue = 0;        tableContent.style.top = `${topValue}px`;        currentRowIndex = 0;        renderDataTable([...tableData, ...tableData]);        targetTop = 0;      }
      scrollState = 'paused';
      pauseTimeoutId = setTimeout(() => {        currentRowIndex++;        targetTop = -currentRowIndex * rowHeight;        scrollState = 'scrolling';        scrollAnimationId = requestAnimationFrame(animateScroll);      }, pauseDuration);    } else {      topValue += distance > 0 ? scrollSpeed : -scrollSpeed;      tableContent.style.top = `${topValue}px`;      scrollAnimationId = requestAnimationFrame(animateScroll);    }  }}

播放暂停控制

startScroll 和 pauseScroll 函数分别负责启动和暂停滚动,同时处理动画帧和定时器的清理工作,防止内存泄漏。
function startScroll() {  if (scrollAnimationId) cancelAnimationFrame(scrollAnimationId);  if (pauseTimeoutId) clearTimeout(pauseTimeoutId);
  if (tableData.length > maxVisibleRows) {    scrollState = 'scrolling';    scrollAnimationId = requestAnimationFrame(animateScroll);  }}
function pauseScroll() {  if (scrollAnimationId) {    cancelAnimationFrame(scrollAnimationId);    scrollAnimationId = null;  }  if (pauseTimeoutId) {    clearTimeout(pauseTimeoutId);    pauseTimeoutId = null;  }}

扩展建议

  • 支持不同滚动速度配置,满足多样化展示需求

  • 增加鼠标悬停暂停功能,提升用户体验

  • 实现数据动态更新机制,支持实时数据展示

完整代码

git地址:https://gitee.com/ironpro/hjdemo/blob/master/table-moveup/index.html
<!DOCTYPE html><html lang="zh-CN"><head>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>表格滚动效果</title>  <style>    body { margin0padding0background-color#0a1a2fdisplay: flex; justify-content: center; align-items: center; min-height100vh; }    .screen-container { width800pxheight490pxbackground-color#0a1a2fpadding20pxborder-radius8pxbox-sizing: border-box; overflow: hidden; display: flex; flex-direction: column; }    .table-title { color#409efffont-size20pxmargin-bottom15pxtext-align: center; flex-shrink0; }    .table-wrapper { width100%flex1margin-bottom10pxdisplay: flex; flex-direction: column; min-height0; }    .table-header { flex-shrink0width100%height42px; }    .header-table.data-table { width100%border-collapse: collapse; color#e5eaf5font-size16pxtable-layout: fixed; }    .header-table th.data-table td { padding0 10pxtext-align: center; box-sizing: border-box; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }    .header-table th:nth-child(1), .data-table td:nth-child(1) { width15%; }    .header-table th:nth-child(2), .data-table td:nth-child(2) { width35%; }    .header-table th:nth-child(3), .data-table td:nth-child(3) { width25%; }    .header-table th:nth-child(4), .data-table td:nth-child(4) { width25%; }    .header-table th { background-color#1e3a5fheight40pxline-height40pxborder1px solid #2d496ebox-sizing: border-box; }    .scroll-table { width100%flex1overflow: hidden; position: relative; border1px solid #2d496ebox-sizing: border-box; min-height0; }    .table-content { position: absolute; top0left0width100%; }    .data-table tr { height52pxline-height50pxbox-sizing: border-box; }    .data-table td { border1px solid #1e3a5fbox-sizing: border-box; height50pxvertical-align: middle; }    .data-table tr:nth-child(odd) { background-colorrgba(3058950.3); }    .data-table tr:hover { background-colorrgba(641582550.2); }    .control-btn { text-align: center; height40pxline-height40px; }    button { padding8px 16pxmargin0 10pxbackground-color#409effcolor: white; border: none; border-radius4pxcursor: pointer; font-size14px; }    button:hover { background-color#66b1ff; }    button:disabled { background-color#909399cursor: not-allowed; }  </style></head><body><div class="screen-container">  <div class="table-title">商品销售排行榜</div>  <div class="table-wrapper">    <div class="table-header">      <table class="header-table">        <tr>          <th>序号</th>          <th>产品名称</th>          <th>数值</th>          <th>增长率</th>        </tr>      </table>    </div>    <div class="scroll-table" id="scrollTable">      <div class="table-content" id="tableContent"></div>    </div>  </div>  <div class="control-btn">    <button id="pauseBtn">暂停滚动</button>    <button id="playBtn" disabled>继续滚动</button>  </div></div>
<script>  const tableData = [    { id1name'产品A'value'9876'rate'+12.5%' },    { id2name'产品B'value'8765'rate'+8.3%' },    { id3name'产品C'value'7654'rate'-2.1%' },    { id4name'产品D'value'6543'rate'+15.7%' },    { id5name'产品E'value'5432'rate'+5.9%' },    { id6name'产品F'value'4321'rate'-1.8%' },    { id7name'产品G'value'3210'rate'+9.2%' },    { id8name'产品H'value'2109'rate'+7.4%' }  ];
  const tableContent = document.getElementById('tableContent');  const scrollTable = document.getElementById('scrollTable');  const pauseBtn = document.getElementById('pauseBtn');  const playBtn = document.getElementById('playBtn');
  let scrollAnimationId = null;  let pauseTimeoutId = null;  let isScrolling = true;  const rowHeight = 52;  let topValue = 0;  let targetTop = 0;  let currentRowIndex = 0;  let scrollSpeed = 2;  let pauseDuration = 1500;  let maxVisibleRows = 0;  let scrollState = 'scrolling';
  function initTable() {    renderDataTable([...tableData, ...tableData]);
    const availableHeight = scrollTable.clientHeight;    maxVisibleRows = Math.floor(availableHeight / rowHeight);
    if (tableData.length <= maxVisibleRows) {      pauseBtn.disabled = true;      playBtn.disabled = true;      pauseBtn.textContent = '数据不足';      return false;    }
    return true;  }
  function renderDataTable(data) {    const tableHtml = `<table class="data-table">        ${data.map(item => `<tr>            <td>${item.id}</td>            <td>${item.name}</td>            <td>${item.value}</td>            <td style="color: ${item.rate.includes('-') ? '#f56c6c' : '#67c23a'}">${item.rate}</td>          </tr>`).join('')}      </table>`;    tableContent.innerHTML = tableHtml;  }
  function animateScroll() {    if (!isScrolling) return;
    if (scrollState === 'scrolling') {      const distance = targetTop - topValue;
      if (Math.abs(distance) <= scrollSpeed) {        topValue = targetTop;        tableContent.style.top = `${topValue}px`;
        if (currentRowIndex >= tableData.length) {          topValue = 0;          tableContent.style.top = `${topValue}px`;          currentRowIndex = 0;          renderDataTable([...tableData, ...tableData]);          targetTop = 0;        }
        scrollState = 'paused';
        pauseTimeoutId = setTimeout(() => {          currentRowIndex++;          targetTop = -currentRowIndex * rowHeight;          scrollState = 'scrolling';          scrollAnimationId = requestAnimationFrame(animateScroll);        }, pauseDuration);      } else {        topValue += distance > 0 ? scrollSpeed : -scrollSpeed;        tableContent.style.top = `${topValue}px`;        scrollAnimationId = requestAnimationFrame(animateScroll);      }    }  }
  function startScroll() {    if (scrollAnimationId) cancelAnimationFrame(scrollAnimationId);    if (pauseTimeoutId) clearTimeout(pauseTimeoutId);
    if (tableData.length > maxVisibleRows) {      scrollState = 'scrolling';      scrollAnimationId = requestAnimationFrame(animateScroll);    }  }
  function pauseScroll() {    if (scrollAnimationId) {      cancelAnimationFrame(scrollAnimationId);      scrollAnimationId = null;    }    if (pauseTimeoutId) {      clearTimeout(pauseTimeoutId);      pauseTimeoutId = null;    }  }
  pauseBtn.addEventListener('click'() => {    if (isScrolling) {      pauseScroll();      isScrolling = false;      pauseBtn.disabled = true;      playBtn.disabled = false;      pauseBtn.textContent = '已暂停';    }  });
  playBtn.addEventListener('click'() => {    if (!isScrolling && tableData.length > maxVisibleRows) {      isScrolling = true;      startScroll();      pauseBtn.disabled = false;      playBtn.disabled = true;      pauseBtn.textContent = '暂停滚动';    }  });
  const isInitable = initTable();  if (isInitable) {    startScroll();  }
  window.addEventListener('beforeunload'() => {    if (scrollAnimationId) {      cancelAnimationFrame(scrollAnimationId);    }    if (pauseTimeoutId) {      clearTimeout(pauseTimeoutId);    }  });</script></body></html>


阅读原文:点击这里


该文章在 2026/1/10 9:33:22 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved