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

如何在React中实现弹性网格布局展示男装上衣商品

React Bootstrap 4×3商品布局+分页实现方案

1. 定义基础数据与状态

先把硬编码的卡片逻辑替换为动态数据驱动,首先定义商品数据结构、分页状态、图片有效性校验逻辑:

  • 每页固定展示12条(4列×3行),不足12条时补全空占位项保证布局稳定
  • 封装图片URL有效性校验函数,支持预校验和加载失败兜底
import { useState, useMemo } from 'react';
import { Card, Row, Col, Pagination } from 'react-bootstrap';

// 工具函数:校验图片URL是否有效
const isValidImageUrl = (url) => {
  return url && typeof url === 'string' && /^(https?:\/\/.*\.(?:png|jpg|jpeg|webp|gif))/i.test(url);
};

// 替换为你实际的商品数据源(接口返回/本地定义都可)
const MOCK_PRODUCT_LIST = [
  { id: 1, name: '休闲纯棉T恤', imgUrl: '你的有效图片地址', price: 99 },
  // 更多商品数据...
];
const PAGE_SIZE = 12;

2. 实现分页逻辑

用useMemo计算当前页需要渲染的列表项,自动补全占位项到12条:

function ProductGrid() {
  const [currentPage, setCurrentPage] = useState(1);

  // 计算总页数
  const totalPage = useMemo(() => {
    return Math.ceil(MOCK_PRODUCT_LIST.length / PAGE_SIZE);
  }, []);

  // 计算当前页展示的项,不足12条补空占位
  const currentPageItems = useMemo(() => {
    const start = (currentPage - 1) * PAGE_SIZE;
    const end = start + PAGE_SIZE;
    const sliced = MOCK_PRODUCT_LIST.slice(start, end);
    // 补全到12个占位项,保证布局始终是3行4列不会错乱
    return [...sliced, ...Array(PAGE_SIZE - sliced.length).fill(null)];
  }, [currentPage]);

3. 实现4×3网格渲染

用Bootstrap栅格系统实现每行4列,有效URL渲染卡片,无效/空项留空:

return (
    <div className="container my-4">
      {/* 商品网格区域 */}
      <Row className="g-3">
        {currentPageItems.map((item, index) => (
          <Col key={index} xs={6} sm={4} md={3}>
            {/* 仅当商品存在且图片URL有效时渲染卡片 */}
            {item && isValidImageUrl(item.imgUrl) ? (
              <Card>
                <Card.Img variant="top" src={item.imgUrl} alt={item.name} 
                  onError={(e) => e.target.parentElement.parentElement.style.display = 'none'} 
                />
                <Card.Body>
                  <Card.Title>{item.name}</Card.Title>
                  <Card.Text>¥{item.price}</Card.Text>
                </Card.Body>
              </Card>
            ) : (
              // 空占位容器,高度和卡片保持一致,避免布局错位
              <div className="w-100" style={{ height: '320px' }} />
            )}
          </Col>
        ))}
      </Row>

      {/* 分页控件,总页数大于1时才显示 */}
      {totalPage > 1 && (
        <Pagination className="mt-4 justify-content-center">
          <Pagination.Prev disabled={currentPage === 1} onClick={() => setCurrentPage(prev => prev - 1)} />
          {Array.from({ length: totalPage }, (_, i) => i + 1).map(page => (
            <Pagination.Item key={page} active={page === currentPage} onClick={() => setCurrentPage(page)}>
              {page}
            </Pagination.Item>
          ))}
          <Pagination.Next disabled={currentPage === totalPage} onClick={() => setCurrentPage(prev => prev + 1)} />
        </Pagination>
      )}
    </div>
  );
}

export default ProductGrid;

补充优化点

  • 上述代码已经加了图片加载失败的兜底逻辑,即使预校验漏判也不会出现裂图
  • 可根据实际设计调整空占位容器的高度、栅格断点参数,适配不同设备的展示需求
  • 如果是大数据量场景,把前端分页逻辑改成接口分页即可,仅需调整currentPage变化时拉取对应页数据的逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:06:05