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

优化原生JS构建HTML表格的加载速度及分页实现咨询

优化表格渲染速度 + 实现分页方案

一、先解决渲染慢的核心问题

原代码循环中反复修改tbody.innerHTML会触发浏览器频繁重排重绘,这是性能瓶颈。改成先拼接所有HTML字符串,一次性插入DOM,能大幅提升渲染效率:

const getdata = async () => {
  const endpoint = "https://my.api.here/beta?nurse=",
    response = await fetch(endpoint + x),
    data = await response.json(),
    Items = data.Items;
  
  tbody.innerHTML = "";
  // 用数组拼接HTML,避免多次字符串拼接的性能损耗
  let rowsHtml = [];
  Items.forEach(itemObj => {
    let { bed, patient_name, status, assigned_nurse_id, need_urgency, need, assigned_nurse, ID, timestamp_created_epoch, patient_id, timestamp_created, room } = itemObj;
    rowsHtml.push(`<tr>
      <td>${bed}</td>
      <td>${patient_name}</td>
      <td>${status}</td>
      <td>${assigned_nurse_id}</td>
      <td>${need_urgency}</td>
      <td>${need}</td>
      <td>${assigned_nurse}</td>
      <td>${ID}</td>
      <td>${timestamp_created_epoch}</td>
      <td>${patient_id}</td>
      <td>${timestamp_created}</td>
      <td>${room}</td>
    </tr>`);
  });
  // 一次性插入所有行
  tbody.innerHTML = rowsHtml.join('');

  // 排序逻辑后续适配分页改造
}

二、实现前端分页功能

1. 添加分页控件HTML

在表格下方插入分页操作区域:

<div class="pagination-controls mt-3">
  <button id="prev-btn" class="btn btn-sm btn-secondary" disabled>上一页</button>
  <span id="page-info" class="mx-2">第 1 页 / 共 0 页</span>
  <button id="next-btn" class="btn btn-sm btn-secondary" disabled>下一页</button>
  <select id="page-size" class="form-select form-select-sm ms-2">
    <option value="20">20条/页</option>
    <option value="50">50条/页</option>
    <option value="100">100条/页</option>
  </select>
</div>

2. 改造JS逻辑,加入分页状态管理

全局保存数据和分页状态,实现分页切换、排序适配:

const selectElement = document.querySelector('.nurses');
const tbody = document.querySelector('#tbody');
const prevBtn = document.querySelector('#prev-btn');
const nextBtn = document.querySelector('#next-btn');
const pageInfo = document.querySelector('#page-info');
const pageSizeSelect = document.querySelector('#page-size');

var x = '';
// 分页状态变量
let allData = []; // 保存所有原始数据
let currentPage = 1;
let pageSize = 20;

selectElement.addEventListener('change', (event) => {
  const result = document.querySelector('.result');
  x = event.target.value;
  result.textContent = `You Chose ${event.target.value}`;
  // 切换护士时重置分页状态
  currentPage = 1;
  getdata(x);
});

// 每页条数切换事件
pageSizeSelect.addEventListener('change', () => {
  pageSize = parseInt(pageSizeSelect.value);
  currentPage = 1;
  renderPage();
});

// 上一页按钮事件
prevBtn.addEventListener('click', () => {
  if (currentPage > 1) {
    currentPage--;
    renderPage();
  }
});

// 下一页按钮事件
nextBtn.addEventListener('click', () => {
  const totalPages = Math.ceil(allData.length / pageSize);
  if (currentPage < totalPages) {
    currentPage++;
    renderPage();
  }
});

const getdata = async () => {
  const endpoint = "https://my.api.here/beta?nurse=",
    response = await fetch(endpoint + x),
    data = await response.json();
  
  allData = data.Items; // 缓存所有数据
  renderPage(); // 渲染第一页
  bindSortEvents(); // 绑定排序事件
};

// 渲染当前页数据
const renderPage = () => {
  tbody.innerHTML = "";
  const startIndex = (currentPage - 1) * pageSize;
  const endIndex = startIndex + pageSize;
  const currentPageData = allData.slice(startIndex, endIndex);
  
  let rowsHtml = [];
  currentPageData.forEach(itemObj => {
    let { bed, patient_name, status, assigned_nurse_id, need_urgency, need, assigned_nurse, ID, timestamp_created_epoch, patient_id, timestamp_created, room } = itemObj;
    rowsHtml.push(`<tr>
      <td>${bed}</td>
      <td>${patient_name}</td>
      <td>${status}</td>
      <td>${assigned_nurse_id}</td>
      <td>${need_urgency}</td>
      <td>${need}</td>
      <td>${assigned_nurse}</td>
      <td>${ID}</td>
      <td>${timestamp_created_epoch}</td>
      <td>${patient_id}</td>
      <td>${timestamp_created}</td>
      <td>${room}</td>
    </tr>`);
  });
  tbody.innerHTML = rowsHtml.join('');
  
  // 更新分页信息和按钮状态
  const totalPages = Math.ceil(allData.length / pageSize);
  pageInfo.textContent = `第 ${currentPage} 页 / 共 ${totalPages} 页`;
  prevBtn.disabled = currentPage === 1;
  nextBtn.disabled = currentPage === totalPages || allData.length === 0;
};

// 绑定表头排序事件(适配分页)
const bindSortEvents = () => {
  // 先移除旧监听,避免重复绑定
  document.querySelectorAll('th').forEach(th => th.removeEventListener('click', sortHandler));
  
  document.querySelectorAll('th').forEach(th => th.addEventListener('click', sortHandler));
};

const sortHandler = function() {
  const idx = Array.from(this.parentNode.children).indexOf(this);
  this.asc = !this.asc; // 切换升降序
  
  // 对全部数据排序,而非当前页
  allData.sort((a, b) => {
    const keys = ['bed', 'patient_name', 'status', 'assigned_nurse_id', 'need_urgency', 'need', 'assigned_nurse', 'ID', 'timestamp_created_epoch', 'patient_id', 'timestamp_created', 'room'];
    const getValue = (obj) => {
      const value = obj[keys[idx]];
      return !isNaN(value) ? Number(value) : value.toString();
    };
    
    const v1 = getValue(this.asc ? a : b);
    const v2 = getValue(this.asc ? b : a);
    
    return typeof v1 === 'number' ? v1 - v2 : v1.localeCompare(v2);
  });
  
  currentPage = 1; // 排序后回到第一页
  renderPage();
};

3. 方案说明

  • 缓存全部数据到allData,分页时仅渲染当前页数据,减少DOM元素数量,提升页面流畅度
  • 排序操作针对全部数据进行,排序后自动回到第一页
  • 分页控件状态随当前页自动更新,禁用无效操作按钮
  • 支持自定义每页显示条数

三、额外优化建议

  • 若数据量持续增长,前端分页会有内存压力,可改为后端分页:请求API时携带page和pageSize参数,由后端返回对应页数据
  • 添加加载状态提示,在请求数据时显示“加载中”,提升用户体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:15:42