使用JavaScript + HTML實現(xiàn)表格滾動效果
一、表格滾動效果
數(shù)據(jù)可視化中的動態(tài)展示能夠有效吸引用戶注意力,特別是在監(jiān)控大屏或排行榜場景中。當(dāng)數(shù)據(jù)量較大而顯示區(qū)域有限時,滾動展示成為一種高效的解決方案。通過平滑的滾動動畫,可以讓用戶在不中斷觀看的情況下瀏覽全部數(shù)據(jù),提升信息獲取效率。本文將介紹如何使用 HTML、CSS 和 JavaScript 實現(xiàn)表格滾動效果。
二、效果演示
這個表格滾動效果模擬了一個商品銷售排行榜的展示界面。頁面頂部顯示表格標(biāo)題,下方是帶有表頭的滾動表格區(qū)域。數(shù)據(jù)行會從底部向上滾動,當(dāng)一行完全滾出視窗后,其后續(xù)行繼續(xù)滾動。整個滾動過程平滑連續(xù),當(dāng)所有數(shù)據(jù)都滾動完成后,會立即回到初始狀態(tài)。

三、系統(tǒng)分析
1.頁面結(jié)構(gòu)
頁面主要包括以下幾個區(qū)域:
1.1 容器區(qū)域
包含整個表格組件的外層容器,設(shè)置了深色背景和合適的尺寸。
<div class="screen-container">
<div class="table-title">商品銷售排行榜</div>
<div class="table-wrapper">
<!-- 表格內(nèi)容 -->
</div>
<div class="control-btn">
<button id="pauseBtn">暫停滾動</button>
<button id="playBtn" disabled>繼續(xù)滾動</button>
</div>
</div>1.2 表頭區(qū)域
固定不動的表格頭部,包含列標(biāo)題,不會隨數(shù)據(jù)滾動。
<div class="table-header">
<table class="header-table">
<tr>
<th>序號</th>
<th>產(chǎn)品名稱</th>
<th>數(shù)值</th>
<th>增長率</th>
</tr>
</table>
</div>1.3 滾動表格區(qū)域
包含實際數(shù)據(jù)內(nèi)容,是滾動效果的主要部分。
<div class="scroll-table" id="scrollTable"> <div class="table-content" id="tableContent"></div> </div>
2 核心功能實現(xiàn)
2.1 數(shù)據(jù)初始化與渲染
首先準(zhǔn)備表格數(shù)據(jù),并根據(jù)容器高度計算最大可見行數(shù)。initTable 函數(shù)負(fù)責(zé)初始化表格內(nèi)容,它復(fù)制原始數(shù)據(jù)以創(chuàng)建循環(huán)效果,并計算可顯示的最大行數(shù)。當(dāng)數(shù)據(jù)量少于最大可見行數(shù)時,自動禁用滾動功能。
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 = '數(shù)據(jù)不足';
return false;
}
return true;
}
2.2 動態(tài)內(nèi)容渲染
renderDataTable 函數(shù)根據(jù)傳入的數(shù)據(jù)動態(tài)生成表格 HTML 內(nèi)容。該函數(shù)不僅渲染基本的表格結(jié)構(gòu),還根據(jù)增長率的正負(fù)值設(shè)置不同的顏色樣式,使數(shù)據(jù)展示更加直觀。
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;
}
2.3 滾動動畫控制
animateScroll 函數(shù)是滾動效果的核心,通過 requestAnimationFrame 實現(xiàn)平滑動畫,并在每行到達(dá)頂部時設(shè)置暫停狀態(tài)。
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);
}
}
}
2.4 播放暫??刂?/h4>
startScroll 和 pauseScroll 函數(shù)分別負(fù)責(zé)啟動和暫停滾動,同時處理動畫幀和定時器的清理工作,防止內(nèi)存泄漏。
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;
}
}
四、擴(kuò)展建議
- 支持不同滾動速度配置,滿足多樣化展示需求
- 增加鼠標(biāo)懸停暫停功能,提升用戶體驗
- 實現(xiàn)數(shù)據(jù)動態(tài)更新機(jī)制,支持實時數(shù)據(jù)展示
五、完整代碼
<!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 { margin: 0; padding: 0; background-color: #0a1a2f; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
.screen-container { width: 800px; height: 490px; background-color: #0a1a2f; padding: 20px; border-radius: 8px; box-sizing: border-box; overflow: hidden; display: flex; flex-direction: column; }
.table-title { color: #409eff; font-size: 20px; margin-bottom: 15px; text-align: center; flex-shrink: 0; }
.table-wrapper { width: 100%; flex: 1; margin-bottom: 10px; display: flex; flex-direction: column; min-height: 0; }
.table-header { flex-shrink: 0; width: 100%; height: 42px; }
.header-table, .data-table { width: 100%; border-collapse: collapse; color: #e5eaf5; font-size: 16px; table-layout: fixed; }
.header-table th, .data-table td { padding: 0 10px; text-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) { width: 15%; }
.header-table th:nth-child(2), .data-table td:nth-child(2) { width: 35%; }
.header-table th:nth-child(3), .data-table td:nth-child(3) { width: 25%; }
.header-table th:nth-child(4), .data-table td:nth-child(4) { width: 25%; }
.header-table th { background-color: #1e3a5f; height: 40px; line-height: 40px; border: 1px solid #2d496e; box-sizing: border-box; }
.scroll-table { width: 100%; flex: 1; overflow: hidden; position: relative; border: 1px solid #2d496e; box-sizing: border-box; min-height: 0; }
.table-content { position: absolute; top: 0; left: 0; width: 100%; }
.data-table tr { height: 52px; line-height: 50px; box-sizing: border-box; }
.data-table td { border: 1px solid #1e3a5f; box-sizing: border-box; height: 50px; vertical-align: middle; }
.data-table tr:nth-child(odd) { background-color: rgba(30, 58, 95, 0.3); }
.data-table tr:hover { background-color: rgba(64, 158, 255, 0.2); }
.control-btn { text-align: center; height: 40px; line-height: 40px; }
button { padding: 8px 16px; margin: 0 10px; background-color: #409eff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }
button:hover { background-color: #66b1ff; }
button:disabled { background-color: #909399; cursor: 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>產(chǎn)品名稱</th>
<th>數(shù)值</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>繼續(xù)滾動</button>
</div>
</div>
<script>
const tableData = [
{ id: 1, name: '產(chǎn)品A', value: '9876', rate: '+12.5%' },
{ id: 2, name: '產(chǎn)品B', value: '8765', rate: '+8.3%' },
{ id: 3, name: '產(chǎn)品C', value: '7654', rate: '-2.1%' },
{ id: 4, name: '產(chǎn)品D', value: '6543', rate: '+15.7%' },
{ id: 5, name: '產(chǎn)品E', value: '5432', rate: '+5.9%' },
{ id: 6, name: '產(chǎn)品F', value: '4321', rate: '-1.8%' },
{ id: 7, name: '產(chǎn)品G', value: '3210', rate: '+9.2%' },
{ id: 8, name: '產(chǎn)品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 = '數(shù)據(jù)不足';
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>以上就是使用JavaScript + HTML實現(xiàn)表格滾動效果的詳細(xì)內(nèi)容,更多關(guān)于JavaScript HTML表格滾動的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript仿靜態(tài)分頁實現(xiàn)方法
這篇文章主要介紹了JavaScript仿靜態(tài)分頁實現(xiàn)方法,可實現(xiàn)模擬靜態(tài)效果的分頁功能,并且可以控制分頁的字符數(shù),使用時可根據(jù)情況進(jìn)行相應(yīng)的字段修改即可,非常靈活實用,需要的朋友可以參考下2015-08-08
Javascript實現(xiàn)簡單的富文本編輯器附演示
這篇文章主要介紹了通過Javascript實現(xiàn)的簡單富文本編輯器,需要的朋友可以參考下2014-06-06
JS使用setInterval計時器實現(xiàn)挑戰(zhàn)10秒
這篇文章主要為大家詳細(xì)介紹了JS使用setInterval計時器實現(xiàn)挑戰(zhàn)10秒,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-11-11

