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

Thymeleaf th:each循环:如何避免生成多余div标签

问题描述

我用Thymeleaf写了这段代码,通过th:each循环渲染数据库里的题目:

<div class="question" th:each="question : ${questions}">
    <h2 id="question" class="description" th:text="${question.description}">Question goes here</h2>
    <div id="answer-buttons">
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(0).content}" th:classappend="${question.correctAnswer == 1 ? 'correct-answer' : ''}">Answer 1</div></button>
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(1).content}" th:classappend="${question.correctAnswer == 2 ? 'correct-answer' : ''}">Answer 2</div></button>
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(2).content}" th:classappend="${question.correctAnswer == 3 ? 'correct-answer' : ''}">Answer 3</div></button>
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(3).content}" th:classappend="${question.correctAnswer == 4 ? 'correct-answer' : ''}">Answer 4</div></button>
    </div>
    <button id="next-btn">Next</button>
</div>

这段代码会为每个题目生成一个带question类的div,但我的JS代码需要解析这些数据,不需要这些多余的HTML包裹元素。我想知道Thymeleaf有没有办法避免生成这些额外的div,还是必须修改代码结构?

我的JS处理代码参考:

const questionsFromDb = document.querySelectorAll('.question');

// 模板数据
const questions = [
    {
        question: "Which is the largest animal on the planet?",
        answers: [
            {text: "Shark", correct: false},
            {text: "Blue whale", correct: true},
            {text: "Elephant", correct: false},
            {text: "Giraffe", correct: false}
        ]
    },
    {
        question: "Which is the smallest country on the planet?",
        answers: [
            {text: "Vatican City", correct: true},
            {text: "Bhutan", correct: false},
            {text: "Nepal", correct: false},
            {text: "Shri Lanka", correct: false}
        ]
    },
    {
        question: "Which is the largest desert on the planet?",
        answers: [
            {text: "Kalahari", correct: false},
            {text: "Gobi", correct: false},
            {text: "Sahara", correct: false},
            {text: "Antarctica", correct: true}
        ]
    },
    {
        question: "Which is the smallest continent on the planet?",
        answers: [
            {text: "Asia", correct: false},
            {text: "Australia", correct: true},
            {text: "Arctic", correct: false},
            {text: "Africa", correct: false}
        ]
    }
];

// 解析HTML中的数据
questionsFromDb.forEach(questionFromDb => {
    const questionDescription = questionFromDb.querySelector('.description').innerText;
    const answerElements = questionFromDb.querySelectorAll('.answer');

    const answers = [];

    answerElements.forEach((answerElement, index) => {
        const answerText = answerElement.innerText;
        const isCorrect = answerElement.classList.contains('correct-answer');

        answers.push({ text: answerText, correct: isCorrect });
    });

    questions.push({
        question: questionDescription,
        answers: answers
    });
});

// 后续代码...
解决方案

Thymeleaf有专门的机制可以避免生成多余的包裹标签,同时也有更高效的方式处理数据传递:

1. 使用**<th:block>**无逻辑标签

<th:block>是Thymeleaf的专用元素,它只执行循环、条件判断等逻辑,不会被渲染成任何HTML标签。把循环移到这个标签上即可:

<th:block th:each="question : ${questions}">
    <h2 class="description" th:text="${question.description}">Question goes here</h2>
    <div class="answer-buttons"> <!-- 注意:原代码里的id="answer-buttons"会重复,改成class避免HTML规范问题 -->
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(0).content}" th:classappend="${question.correctAnswer == 1 ? 'correct-answer' : ''}">Answer 1</div></button>
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(1).content}" th:classappend="${question.correctAnswer == 2 ? 'correct-answer' : ''}">Answer 2</div></button>
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(2).content}" th:classappend="${question.correctAnswer == 3 ? 'correct-answer' : ''}">Answer 3</div></button>
        <button class="btn"><div class="answer" th:text="${question.possibleAnswers.get(3).content}" th:classappend="${question.correctAnswer == 4 ? 'correct-answer' : ''}">Answer 4</div></button>
    </div>
    <button class="next-btn">Next</button> <!-- 同样把id改成class,避免重复id -->
</th:block>

渲染后只会生成每个题目的标题、按钮组和下一步按钮,不会有外层的question div。

2. 更高效的方案:直接传递JSON数据

既然JS最终要把数据转成对象数组,完全可以跳过HTML解析步骤,直接在后端把questions数据转成JSON输出到页面:

<script th:inline="javascript">
    // 直接从后端获取JSON格式的题目数据
    const questionsFromDb = /*[[${questions}]]*/ [];
    
    // 转换为JS需要的格式
    const formattedQuestions = questionsFromDb.map(question => {
        return {
            question: question.description,
            answers: question.possibleAnswers.map((ans, index) => ({
                text: ans.content,
                correct: question.correctAnswer === index + 1
            }))
        };
    });
    
    // 合并到现有数据
    const questions = [
        // 你的模板数据...
    ].concat(formattedQuestions);
</script>

这种方式不需要生成任何多余HTML,也避免了JS解析DOM的开销,效率更高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:56:13