You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

纯JavaScript实现表格数据分页(仅保留上一页/下一页按钮)技术咨询

纯JavaScript实现表格分页(仅上下页按钮+自定义每页条数)

首先,我先帮你梳理现有代码的问题,然后提供一个完全符合需求的原生JS实现方案——不需要任何框架,支持选择10/20/50/100条或全部数据,仅保留上一页、下一页按钮。

现有代码的核心问题

  1. 变量作用域混乱:nbElement未全局初始化,导致分页逻辑无法正确获取当前每页条数
  2. 分页判断逻辑错误:上下页跳转条件不符合数据范围,比如下一页未判断是否超出总数据长度
  3. 初始渲染缺失:数据加载完成后没有默认渲染第一页内容
  4. 全量数据处理缺失:选择"All"时没有正确展示所有数据,也未处理分页按钮状态
  5. 按钮状态未管理:第一页时上一页按钮应禁用,最后一页时下一页按钮应禁用,提升用户体验

修正后的完整实现

HTML代码(调整结构与闭合问题,添加基础样式)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Superheroes Database</title>
    <style>
        .tableau { border-collapse: collapse; width: 100%; margin-top: 20px; }
        .tableau th, .tableau td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        .tableau th { background-color: #f2f2f2; }
        .btn-page { padding: 8px 16px; margin: 10px 5px; cursor: pointer; border: none; border-radius: 4px; background-color: #4CAF50; color: white; }
        .btn-page:disabled { cursor: not-allowed; opacity: 0.5; background-color: #ccc; }
        .custom-select, .selector { margin-right: 8px; }
    </style>
</head>
<body id="my-page">
    <h1>Superheroes Database</h1>
    <br><br>
    <p>All of them in one place</p>
    <br><br>
    <input type="text" id="search" placeholder="Search for names...">
    <form>
        <label class="selector" for="th-select">Search by...</label>
        <select id="th-list">
            <option value="name">NAME</option>
            <option value="fullName">FULL NAME</option>
            <option value="race">RACE</option>
            <option value="intelligence">POWERSTATS (Intelligence)</option>
            <option value="strength">POWERSTATS (Strength)</option>
            <option value="speed">POWERSTATS (Speed)</option>
            <option value="durability">POWERSTATS (Durability)</option>
            <option value="power">POWERSTATS (Power)</option>
            <option value="combat">POWERSTATS (Combat)</option>
            <option value="gender">GENDER</option>
            <option value="placeOfBirth">PLACE OF BIRTH</option>
            <option value="alignment">ALIGNMENT</option>
            <option value="any" selected>ANY</option>
        </select>
    </form>
    <form>
        <label class="custom-select" for="maxRows-select">Elements per page: </label>
        <select id="maxRows">
            <option value="10">10</option>
            <option value="20" selected>20</option>
            <option value="50">50</option>
            <option value="100">100</option>
            <option value="all">All</option>
        </select>
    </form>
    <p id="no-result"></p>
    <button class="btn-page" id="btn-previous" disabled> ← Previous </button>
    <button class="btn-page" id="btn-next"> Next → </button>

    <!-- TABLE CONSTRUCTION -->
    <table id="table" class="tableau" style="width:100%">
        <thead>
            <tr>
                <th rowspan="2">Picture</th>
                <th rowspan="2">Name</th>
                <th rowspan="2">Full Name</th>
                <th rowspan="2">Powerstats</th>
                <th rowspan="2">Race</th>
                <th rowspan="2">Gender</th>
                <th rowspan="2">Height</th>
                <th rowspan="2">Weight</th>
                <th rowspan="2">Place of Birth</th>
                <th rowspan="2">Alignment</th>
            </tr>
        </thead>
        <tbody id="data"></tbody>
    </table>

    <script src="script.js"></script>
</body>
</html>

JavaScript代码(重写分页逻辑,修复所有问题)

// 全局状态管理
let characters = [];
let currentOffset = 0;
let itemsPerPage = 20; // 默认每页20条
const dataContainer = document.getElementById("data");
const prevBtn = document.getElementById("btn-previous");
const nextBtn = document.getElementById("btn-next");
const rowsSelector = document.getElementById("maxRows");
const noResultEl = document.getElementById("no-result");

// 异步加载英雄数据
async function fetchHeroes() {
    try {
        const response = await fetch('https://rawcdn.githack.com/akabab/superhero-api/0.2.0/api/all.json');
        characters = await response.json();
        console.log(`Loaded ${characters.length} heroes`);
        renderPage();
    } catch (error) {
        noResultEl.textContent = "Failed to load hero data. Please try again later.";
        console.error("Fetch error:", error);
    }
}

// 渲染当前页内容
function renderPage() {
    if (characters.length === 0) return;

    let endIndex;
    // 处理全量数据的情况
    if (itemsPerPage === "all") {
        endIndex = characters.length;
        prevBtn.disabled = true;
        nextBtn.disabled = true;
    } else {
        const perPage = parseInt(itemsPerPage);
        endIndex = currentOffset + perPage;
        // 确保不超出数据范围
        if (endIndex > characters.length) endIndex = characters.length;
        // 更新按钮状态
        prevBtn.disabled = currentOffset === 0;
        nextBtn.disabled = endIndex >= characters.length;
    }

    // 生成表格行,处理空字段
    let tableHTML = "";
    for (let i = currentOffset; i < endIndex; i++) {
        const hero = characters[i];
        tableHTML += `
            <tr>
                <td><img src="${hero.images.xs}" alt="${hero.name}"></td>
                <td class="hero-name">${hero.name}</td>
                <td class="hero-fullname">${hero.biography.fullName || "N/A"}</td>
                <td class="hero-powerstats">
                    Int: ${hero.powerstats.intelligence}, 
                    Str: ${hero.powerstats.strength}, 
                    Spd: ${hero.powerstats.speed}, 
                    Dur: ${hero.powerstats.durability}, 
                    Pwr: ${hero.powerstats.power}, 
                    Cmb: ${hero.powerstats.combat}
                </td>
                <td class="hero-race">${hero.appearance.race || "N/A"}</td>
                <td class="hero-gender">${hero.appearance.gender || "N/A"}</td>
                <td class="hero-height">${hero.appearance.height.join(", ")}</td>
                <td class="hero-weight">${hero.appearance.weight.join(", ")}</td>
                <td class="hero-placeOfBirth">${hero.biography.placeOfBirth || "N/A"}</td>
                <td class="hero-alignment">${hero.biography.alignment || "N/A"}</td>
            </tr>
        `;
    }

    dataContainer.innerHTML = tableHTML;
}

// 上一页按钮事件
prevBtn.addEventListener("click", () => {
    const perPage = parseInt(itemsPerPage);
    if (currentOffset - perPage >= 0) {
        currentOffset -= perPage;
        renderPage();
    }
});

// 下一页按钮事件
nextBtn.addEventListener("click", () => {
    const perPage = parseInt(itemsPerPage);
    const nextOffset = currentOffset + perPage;
    if (nextOffset < characters.length) {
        currentOffset = nextOffset;
        renderPage();
    }
});

// 每页条数选择事件
rowsSelector.addEventListener("change", () => {
    itemsPerPage = rowsSelector.value;
    currentOffset = 0; // 切换条数后回到第一页
    renderPage();
});

// 初始化加载数据
fetchHeroes();

关键逻辑说明

  1. 全局状态管理:用全局变量统一管理数据、当前偏移量、每页条数,避免作用域冲突
  2. 异步数据加载:使用async/await确保数据加载完成后再渲染,添加错误处理提升健壮性
  3. 分页渲染优化:
    • 动态计算当前页的起始/结束索引,确保不超出数据范围
    • 选择"All"时直接渲染所有数据,并禁用分页按钮
    • 自动更新按钮禁用状态,第一页禁用上一页,最后一页禁用下一页
  4. 用户交互优化:切换每页条数时自动回到第一页,保证体验一致性
  5. 数据容错处理:对可能为空的字段添加N/A默认值,避免页面显示异常

内容的提问来源于stack exchange,提问作者Hyou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 09:47:32