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

React Next.js动态Grid布局:实现可扩展的卡片展开效果

动态实现网格卡片展开布局的方案

核心思路:放弃静态grid-area,改用动态计算grid-row + 响应式列数控制

不用手动定义grid-A1这类固定类,而是通过计算卡片索引来动态设置行位置,同时利用Tailwind的响应式工具和CSS变量适配不同断点的列数,彻底摆脱行数限制。


步骤1:配置网格容器

确保容器使用自动行高,让行高随内容自适应,避免固定行高限制扩展:

<div className="grid gap-4 grid-cols-5 md:grid-cols-2 grid-template-rows:auto">
  {/* 卡片及展开内容将渲染在这里 */}
</div>

这里grid-cols-5对应桌面端5列布局,md:grid-cols-2对应移动端2列布局(可根据你的断点需求调整)。

步骤2:动态计算卡片行位置

渲染卡片时,根据当前断点的列数,计算主卡片所在的行,展开的子卡片直接放在主卡片的下一行:

// 根据窗口宽度获取当前列数,或用CSS变量优化(见步骤3)
const getCurrentColumns = () => {
  return window.innerWidth >= 768 ? 5 : 2;
};

// 遍历渲染卡片
cards.map((card, index) => {
  const columns = getCurrentColumns();
  const cardRow = Math.floor(index / columns) + 1; // 计算主卡片所在行

  return (
    <>
      <div 
        className="p-4 bg-white rounded shadow cursor-pointer"
        style={{ gridRow: cardRow }}
        onClick={() => setSelectedIndex(selectedIndex === index ? null : index)}
      >
        <h3>{card.title}</h3>
        <button>{selectedIndex === index ? '收起' : '展开'}</button>
      </div>

      {/* 展开的子卡片,跨整行 */}
      {selectedIndex === index && (
        <div 
          className="col-span-full p-4 bg-gray-50 rounded shadow"
          style={{ gridRow: cardRow + 1 }}
        >
          {card.content}
        </div>
      )}
    </>
  );
})

步骤3:用CSS变量优化断点适配(可选)

避免JS硬编码断点值,用CSS变量统一管理不同断点的列数:

/* 在全局样式或Tailwind的@layer base中添加 */
:root {
  --grid-cols: 5;
}

@media (max-width: 768px) {
  :root {
    --grid-cols: 2;
  }
}

然后在JS中读取变量,无需判断窗口宽度:

const columns = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--grid-cols'));

步骤4:自定义Tailwind工具类简化样式(可选)

如果不想写内联样式,可以自定义工具类配合CSS变量:

@layer utilities {
  .card-row {
    grid-row: var(--card-row);
  }
  .expanded-row {
    grid-row: calc(var(--card-row) + 1);
  }
}

组件中使用方式:

<div 
  className="p-4 bg-white rounded shadow cursor-pointer card-row"
  style={{ '--card-row': cardRow }}
  onClick={() => setSelectedIndex(selectedIndex === index ? null : index)}
>
  <h3>{card.title}</h3>
  <button>{selectedIndex === index ? '收起' : '展开'}</button>
</div>

{selectedIndex === index && (
  <div className="col-span-full p-4 bg-gray-50 rounded shadow expanded-row">
    {card.content}
  </div>
)}

方案优势

  • 无需手动配置任何固定行类,新增卡片自动适配行数
  • 响应式列数仅需在一处修改,移动端多列场景也能自动计算行位置
  • 网格行高随内容自适应,不会出现内容溢出或空白浪费问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:06:16