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

如何使用Thymeleaf遍历集合实现HTML表格每行固定显示4列

解答
  • 把Map转为ArrayList当然可以实现每行4列的效果,但不需要特意做这个转换,不管是Map还是List结构,核心只需要把待遍历元素按每4个分为一组,每组渲染为一行即可实现需求。
  • 以下是几种可直接落地的实现方案,按需选择即可:

方案1:纯Thymeleaf逻辑实现(无需改后端、无需额外CSS)

不管你保留原有Map传值还是换成ArrayList,都可以用Thymeleaf内置工具+循环逻辑实现4列布局,不需要调整后端代码。
首先先修正你原有代码的语法错误:input标签的id属性少了闭合的},也没加th:前缀,正确写法应该是th:id="${element.key}",否则属性值会解析失败。

写法1(推荐,适配Thymeleaf 3.1+版本)

直接用Thymeleaf内置的分区工具#lists.partition(),把元素按每4个一组自动拆分,外层循环遍历每组生成<tr>行标签,内层循环遍历组内元素生成<td>列标签即可。
如果继续用Map传值,代码参考:

<table>
    <!-- 把Map的entry集合转为List,按每4个元素分一组,外层循环生成行 -->
    <tr th:each="group : ${#lists.partition(#maps.entrySet(elementMap), 4)}">
        <!-- 内层循环当前组的元素,生成列 -->
        <td th:each="element : ${group}">
            <div th:text="${element.key}"></div>
            <input type="text" th:id="${element.key}" th:name="${element.key}" th:value="${element.value}" />
        </td>
        <!-- 补全最后一行不足4列的空单元格,避免表格边框、对齐错位 -->
        <td th:each="i : ${#numbers.sequence(4 - group.size(), 1)}" th:if="${group.size() < 4}"></td>
    </tr>
</table>

如果你已经把Map转成了ArrayList传值,只需要把分区方法的第一个参数换成你的ArrayList变量名,其他逻辑完全一致。

写法2(兼容低版本Thymeleaf)

如果你的Thymeleaf版本低于3.1,没有partition工具,可以借助循环步长控制手动分组,用<th:block>作为纯逻辑容器(不会生成多余HTML标签):

<table>
    <th:block th:with="elementList=${#maps.entrySet(elementMap)}, total=${elementList.size()}">
        <!-- 外层按步长4循环,每次生成一行 -->
        <th:block th:each="rowStart : ${#numbers.sequence(0, total - 1, 4)}">
            <tr>
                <!-- 内层循环4次生成列,超出总元素数量时不渲染 -->
                <td th:each="colOffset : ${#numbers.sequence(0, 3)}" th:if="${rowStart + colOffset < total}">
                    <div th:text="${elementList[rowStart + colOffset].key}"></div>
                    <input type="text" th:id="${elementList[rowStart + colOffset].key}" th:name="${elementList[rowStart + colOffset].key}" th:value="${elementList[rowStart + colOffset].value}" />
                </td>
                <!-- 补全最后一行的空单元格 -->
                <td th:each="colOffset : ${#numbers.sequence(0, 3)}" th:if="${rowStart + colOffset >= total}"></td>
            </tr>
        </th:block>
    </th:block>
</table>

方案2:纯CSS实现(代码量最少,维护成本最低)

如果你不强制要求用原生<table>标签做布局,完全不需要调整Thymeleaf的循环逻辑,用CSS Grid可以自动实现4列排列,连手动生成分组、行标签的步骤都省了。
你只需要把原有循环的外层换成普通容器,代码如下:

<!-- 外层容器 -->
<div class="form-grid">
    <div class="grid-item" th:each="element : ${elementMap}">
        <div th:text="${element.key}"></div>
        <input type="text" th:id="${element.key}" th:name="${element.key}" th:value="${element.value}" />
    </div>
</div>

对应加几行CSS即可:

.form-grid {
    display: grid;
    /* 固定生成4列,每列宽度自适应 */
    grid-template-columns: repeat(4, 1fr);
    /* 自行调整行、列间距 */
    gap: 16px;
}

这种写法不需要关心元素总个数、分组逻辑,浏览器会自动完成排列。后续如果要调整成每行3列、5列,只需要改CSS里的一个数字;做响应式适配也很方便,小屏设备下自动换成2列、1列只需要加几行媒体查询,灵活性远高于原生table布局。
如果你一定要用table标签,也可以给td设置固定宽度让表格自动换行,但这种方式对单元格高度不一致的场景兼容很差,不推荐。


方案3:后端提前分组(模板逻辑最干净)

如果你不想在模板里写太多判断逻辑,可以直接在后端把数据提前分好组:不管是Map还是ArrayList,都封装成List<List<元素类型>>的结构,每4个元素存为一个子List,所有子List组成大List传到前端。
前端只需要两层简单循环即可,不需要写任何判断:

<table>
    <tr th:each="group : ${groupedList}">
        <td th:each="element : ${group}">
            <div th:text="${element.key}"></div>
            <input type="text" th:id="${element.key}" th:name="${element.key}" th:value="${element.value}" />
        </td>
    </tr>
</table>

这种方式的好处是模板逻辑非常简洁,后续如果要调整每行的列数,只需要改后端分组规则即可,不需要动模板代码。

注意:如果用原生table布局,最后一行元素不足4个时一定要补全空<td>,否则表格的边框、对齐会出现错位;如果用CSS Grid/Flex布局则不需要考虑这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:01:47