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
相关产品推荐
相关产品推荐

