HTML 表格中实现每行显示两个数据项的正确写法

作者:袖梨 2026-07-18

本文详解如何在 Thymeleaf 模板中结合 HTML <table> 标签,优雅地将单列表数据(如数据库查询结果)以“每行两列”的布局渲染,避免常见误区(如错误嵌套 th:each 在 <table> 上),并提供可直接运行的结构化代码与关键注意事项。

本文详解如何在 thymeleaf 模板中结合 html `

在 HTML 表格中实现“每行显示两个数据项”(例如图书/歌手卡片并排展示),关键在于正确理解表格语义结构:<table> 定义整体容器,<tr> 表示一行,<td> 表示该行中的单元格。初学者常误将 th:each 直接放在 <table> 上(如原代码),导致每个数据项生成一个独立表格,完全破坏布局逻辑。

正确的做法是:在外层 <table> 中遍历数据索引,按步长为 2 动态生成 <tr> 行,并在每行内通过索引计算填充两个 <td> 单元格。以下是优化后的完整代码:

<table class="vocalist-table">  <tr th:each="vocalist, iterStat : ${bookList}"       th:if="${iterStat.index % 2 == 0}">    <!-- 左侧单元格:当前索引项 -->    <td>      <div class="bookdiv" th:id="'vocalist-' + ${iterStat.index}">        <img src="images/ClosedBook.png" class="closeBook" alt="Book cover">        <span class="bookName" th:text="${vocalist.vocaName}">Vocalist Name</span>      </div>    </td>    <!-- 右侧单元格:下一索引项(需校验不越界) -->    <td th:if="${iterStat.index + 1 < bookList.size()}">      <div class="bookdiv" th:id="'vocalist-' + ${iterStat.index + 1}">        <img src="images/ClosedBook.png" class="closeBook" alt="Book cover">        <span class="bookName"               th:text="${bookList[iterStat.index + 1].vocaName}">Vocalist Name</span>      </div>    </td>  </tr></table>

核心要点说明:

  • th:each 必须作用于 <tr>(而非 <table> 或 <td>),确保每轮迭代生成一行;
  • 使用 iterStat.index % 2 == 0 控制仅在偶数索引(0, 2, 4…)时创建新行,自然形成“每行处理两项”的节奏;
  • 右侧 <td> 的 th:if 条件防止访问 bookList[size] 导致索引越界(当列表长度为奇数时,最后一行仅渲染左侧一项);
  • 为每个 div.bookdiv 添加动态 id(如 vocalist-0),便于后续 JavaScript 交互或样式定位,避免重复 ID(原代码中所有元素 id="startButton" 违反 HTML 规范)。

⚠️ 重要注意事项:

立即学习“前端免费学习笔记(深入)”;

  • 若追求更高灵活性与响应式(如移动端单列、桌面端双列),推荐改用 CSS Grid 或 Flexbox:它们语义更清晰、维护性更强,且无需手动索引计算。例如:
    .vocalist-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }@media (max-width: 768px) { .vocalist-grid { grid-template-columns: 1fr; } }
  • Thymeleaf 中避免在模板中进行复杂逻辑运算;若数据量大或逻辑复杂,建议在 Controller 层预处理为二维列表(如 List<List<Vocalist>>),再用嵌套 th:each 渲染,提升可读性与性能。

此方案兼顾语义正确性、浏览器兼容性与 Thymeleaf 最佳实践,可稳定支撑中等规模数据的双列表格展示需求。

相关文章

精彩推荐