js商品分页功能

admin 106 0
JS商品分页功能主要用于解决大量商品数据的高效展示问题,通过前后端协作实现,前端发送包含页码、每页数量的请求至后端,后端返回对应分页数据,前端动态渲染商品列表及分页控件(如上一页、下一页、页码跳转),并处理边界状态(如首页禁用上一页按钮),该功能优化页面加载性能,提升用户浏览体验,避免数据冗余加载,支持快速定位目标商品。

JavaScript实现商品分页功能:从基础到实战

在电商网站或商品展示类应用中,商品列表通常数据量庞大,直接全部加载会导致页面响应迟缓、用户体验大幅下降。分页功能通过将海量数据合理拆分为多个页面展示,既能有效减轻前端渲染压力,又能显著提升用户浏览效率,本文将深入探讨如何使用原生JavaScript实现商品分页功能,涵盖核心逻辑、完整代码实现以及用户体验优化策略。

分页功能的核心概念与关键参数

在实现分页功能前,我们需要明确几个贯穿前后端交互与前端渲染的核心参数:

当前页码(currentPage)

用户当前正在查看的页码,从1开始计数(例如第1页、第2页),在状态管理中,这个值会随着用户操作而动态变化。

每页显示数量(pageSize)

每页展示的商品数量,常见的有10、20、50条等,这个参数应根据业务需求和数据特点进行合理设置,通常提供用户可选项以增强灵活性。

总数据量(totalItems)

所有商品的总数量(例如共120件商品),通常由后端API返回,是计算总页数的基础数据。

总页数(totalPages)

通过总数据量和每页数量计算得出,公式为:

totalPages = Math.ceil(totalItems / pageSize)

注意:使用Math.ceil向上取整,确保余数情况下的页码完整性,避免数据遗漏。

数据偏移量(offset)

当前页数据在总数据中的起始位置,用于后端查询分页数据,公式为:

offset = (currentPage - 1) * pageSize

前端实现步骤:从数据获取到渲染

商品分页的前端实现主要分为四个关键步骤:获取分页数据渲染商品列表生成分页控件处理分页交互,下面通过原生JavaScript逐步实现一个完整的分页系统。

模拟后端数据与API接口

实际开发中,分页数据由后端提供,这里我们使用模拟数据(mockData)和模拟API(fetchProducts)来演示前端逻辑:

// 模拟商品数据(共55条,每页展示10条时,总页数为6)
const mockData = Array.from({ length: 55 }, (_, index) => ({
  id: index + 1,
  name: `商品${index + 1}`,
  price: (Math.random() * 1000 + 100).toFixed(2),
  image: `https://picsum.photos/seed/product${index + 1}/150/150.jpg`,
  description: `这是商品${index + 1}的详细描述,包含产品特点和使用说明,`
}));
// 模拟后端API:根据页码和每页数量获取商品数据
async function fetchProducts(page, pageSize) {
  // 模拟网络延迟(500ms)
  await new Promise(resolve => setTimeout(resolve, 500));
  // 输入验证
  if (page < 1 || pageSize < 1) {
    throw new Error('页码和每页数量必须大于0');
  }
  const offset = (page - 1) * pageSize;
  const items = mockData.slice(offset, offset + pageSize);
  const totalItems = mockData.length;
  return { 
    items, 
    totalItems,
    currentPage: page,
    pageSize: pageSize
  };
}

渲染商品列表

定义一个函数renderProductList,根据传入的商品数据动态生成DOM并插入页面,同时添加加载状态和错误处理:

// 获取商品列表容器
const productListEl = document.getElementById('product-list');
const loadingIndicator = document.getElementById('loading');
// 渲染商品列表
function renderProductList(products) {
  // 显示加载状态
  loadingIndicator.style.display = 'block';
  productListEl.innerHTML = '';
  // 使用requestAnimationFrame优化渲染性能
  requestAnimationFrame(() => {
    try {
      const productHTML = products.map(product => `
        <div class="product-item" data-id="${product.id}">
          <div class="product-image">
            <img src="${product.image}" alt="${product.name}" loading="lazy">
          </div>
          <div class="product-info">
            <h3 class="product-name">${product.name}</h3>
            <p class="product-description">${product.description}</p>
            <div class="product-footer">
              <span class="product-price">¥${product.price}</span>
              <button class="add-to-cart" data-id="${product.id}">加入购物车</button>
            </div>
          </div>
        </div>
      `).join('');
      productListEl.innerHTML = productHTML;
      // 添加产品点击事件
      document.querySelectorAll('.add-to-cart').forEach(btn => {
        btn.addEventListener('click', handleAddToCart);
      });
    } catch (error) {
      console.error('渲染商品列表时出错:', error);
      productListEl.innerHTML = '<div class="error-message">加载商品失败,请稍后重试</div>';
    } finally {
      loadingIndicator.style.display = 'none';
    }
  });
}

生成分页控件

分页控件通常包括:上一页按钮页码按钮下一页按钮跳转输入框等,我们定义renderPagination函数,并添加智能页码显示逻辑:

// 获取分页控件容器
const paginationEl = document.getElementById('pagination');
// 渲染分页控件
function renderPagination(currentPage, totalPages) {
  let paginationHTML = '';
  // 上一页按钮(当前页为1时禁用)
  paginationHTML += `
    <button class="page-btn prev-btn" ${currentPage === 1 ? 'disabled' : ''} data-page="${currentPage - 1}">
      <span class="icon">←</span> 上一页
    </button>
  `;
  // 页码按钮(智能显示:当前页前后2页,避免页码过多)
  const startPage = Math.max(1, currentPage - 2);
  const endPage = Math.min(totalPages, currentPage + 2);
  // 首页
  if (startPage > 1) {
    paginationHTML += `<button class="page-btn" data-page="1">1</button>`;
    if (startPage > 2) {
      paginationHTML += `<span class="page-ellipsis">...</span>`;
    }
  }
  // 中间页码
  for (let i = startPage; i <= endPage; i++) {
    paginationHTML += `
      <button class="page-btn ${i === currentPage ? 'active' : ''}" data-page="${i}">
        ${i}
      </button>
    `;
  }
  // 末页
  if (endPage < totalPages) {
    if (endPage < totalPages - 1) {
      paginationHTML += `<span class="page-ellipsis">...</span>`;
    }
    paginationHTML += `<button class="page-btn" data-page="${totalPages}">${totalPages}</button>`;
  }
  // 下一页按钮(当前页为最后一页时禁用)
  paginationHTML += `
    <button class="page-btn next-btn" ${currentPage === totalPages ? 'disabled' : ''} data-page="${currentPage + 1}">
      下一页 <span class="icon">→</span>
    </button>
  `;

标签: #js #分页