8.4 移除模版片段

回到示例应用,让我们再看看最后一版的产品列表模版:

  1. <table>
  2. <tr>
  3. <th>NAME</th>
  4. <th>PRICE</th>
  5. <th>IN STOCK</th>
  6. <th>COMMENTS</th>
  7. </tr>
  8. <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
  9. <td th:text="${prod.name}">Onions</td>
  10. <td th:text="${prod.price}">2.41</td>
  11. <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  12. <td>
  13. <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
  14. <a href="comments.html"
  15. th:href="@{/product/comments(prodId=${prod.id})}"
  16. th:unless="${#lists.isEmpty(prod.comments)}">view</a>
  17. </td>
  18. </tr>
  19. </table>

这段代码作为模版还好,但如果是一个静态页面(当直接由浏览器打开,而不是由Thymeleaf处理时),就称不上是一个好的原型了。

为什么呢?因为,尽管浏览器完美地表示了,但是表格只有一行,这行还是假数据。作为原型,看起来不够真实······我们应当有多个产品,我们需要更多行。

那就让我们加一些:

  1. <table>
  2. <tr>
  3. <th>NAME</th>
  4. <th>PRICE</th>
  5. <th>IN STOCK</th>
  6. <th>COMMENTS</th>
  7. </tr>
  8. <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
  9. <td th:text="${prod.name}">Onions</td>
  10. <td th:text="${prod.price}">2.41</td>
  11. <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  12. <td>
  13. <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
  14. <a href="comments.html"
  15. th:href="@{/product/comments(prodId=${prod.id})}"
  16. th:unless="${#lists.isEmpty(prod.comments)}">view</a>
  17. </td>
  18. </tr>
  19. <tr class="odd">
  20. <td>Blue Lettuce</td>
  21. <td>9.55</td>
  22. <td>no</td>
  23. <td>
  24. <span>0</span> comment/s
  25. </td>
  26. </tr>
  27. <tr>
  28. <td>Mild Cinnamon</td>
  29. <td>1.99</td>
  30. <td>yes</td>
  31. <td>
  32. <span>3</span> comment/s
  33. <a href="comments.html">view</a>
  34. </td>
  35. </tr>
  36. </table>

好的,现在我们有三行了。对原型来说,绝对比之前更好。但是······当我们用Thymeleaf处理的时候,会发生什么呢?

  1. <table>
  2. <tr>
  3. <th>NAME</th>
  4. <th>PRICE</th>
  5. <th>IN STOCK</th>
  6. <th>COMMENTS</th>
  7. </tr>
  8. <tr>
  9. <td>Fresh Sweet Basil</td>
  10. <td>4.99</td>
  11. <td>yes</td>
  12. <td>
  13. <span>0</span> comment/s
  14. </td>
  15. </tr>
  16. <tr class="odd">
  17. <td>Italian Tomato</td>
  18. <td>1.25</td>
  19. <td>no</td>
  20. <td>
  21. <span>2</span> comment/s
  22. <a href="/gtvg/product/comments?prodId=2">view</a>
  23. </td>
  24. </tr>
  25. <tr>
  26. <td>Yellow Bell Pepper</td>
  27. <td>2.50</td>
  28. <td>yes</td>
  29. <td>
  30. <span>0</span> comment/s
  31. </td>
  32. </tr>
  33. <tr class="odd">
  34. <td>Old Cheddar</td>
  35. <td>18.75</td>
  36. <td>yes</td>
  37. <td>
  38. <span>1</span> comment/s
  39. <a href="/gtvg/product/comments?prodId=4">view</a>
  40. </td>
  41. </tr>
  42. <tr class="odd">
  43. <td>Blue Lettuce</td>
  44. <td>9.55</td>
  45. <td>no</td>
  46. <td>
  47. <span>0</span> comment/s
  48. </td>
  49. </tr>
  50. <tr>
  51. <td>Mild Cinnamon</td>
  52. <td>1.99</td>
  53. <td>yes</td>
  54. <td>
  55. <span>3</span> comment/s
  56. <a href="comments.html">view</a>
  57. </td>
  58. </tr>
  59. </table>

最后两行是假数据!遍历只应用在第一行,所以后两行不应该出现。

我们需要在模版处理时移除那两行。让我们在第二、第三个<tr>标签上使用th:remove属性:

  1. <table>
  2. <tr>
  3. <th>NAME</th>
  4. <th>PRICE</th>
  5. <th>IN STOCK</th>
  6. <th>COMMENTS</th>
  7. </tr>
  8. <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
  9. <td th:text="${prod.name}">Onions</td>
  10. <td th:text="${prod.price}">2.41</td>
  11. <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  12. <td>
  13. <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
  14. <a href="comments.html"
  15. th:href="@{/product/comments(prodId=${prod.id})}"
  16. th:unless="${#lists.isEmpty(prod.comments)}">view</a>
  17. </td>
  18. </tr>
  19. <tr class="odd" th:remove="all">
  20. <td>Blue Lettuce</td>
  21. <td>9.55</td>
  22. <td>no</td>
  23. <td>
  24. <span>0</span> comment/s
  25. </td>
  26. </tr>
  27. <tr th:remove="all">
  28. <td>Mild Cinnamon</td>
  29. <td>1.99</td>
  30. <td>yes</td>
  31. <td>
  32. <span>3</span> comment/s
  33. <a href="comments.html">view</a>
  34. </td>
  35. </tr>
  36. </table>

模版处理后,正常显示:

  1. <table>
  2. <tr>
  3. <th>NAME</th>
  4. <th>PRICE</th>
  5. <th>IN STOCK</th>
  6. <th>COMMENTS</th>
  7. </tr>
  8. <tr>
  9. <td>Fresh Sweet Basil</td>
  10. <td>4.99</td>
  11. <td>yes</td>
  12. <td>
  13. <span>0</span> comment/s
  14. </td>
  15. </tr>
  16. <tr class="odd">
  17. <td>Italian Tomato</td>
  18. <td>1.25</td>
  19. <td>no</td>
  20. <td>
  21. <span>2</span> comment/s
  22. <a href="/gtvg/product/comments?prodId=2">view</a>
  23. </td>
  24. </tr>
  25. <tr>
  26. <td>Yellow Bell Pepper</td>
  27. <td>2.50</td>
  28. <td>yes</td>
  29. <td>
  30. <span>0</span> comment/s
  31. </td>
  32. </tr>
  33. <tr class="odd">
  34. <td>Old Cheddar</td>
  35. <td>18.75</td>
  36. <td>yes</td>
  37. <td>
  38. <span>1</span> comment/s
  39. <a href="/gtvg/product/comments?prodId=4">view</a>
  40. </td>
  41. </tr>
  42. </table>

那个属性里的all值是什么意思呢🤔?th:remove依据它的值,有五种表现形式:

  • all: 移除所在的标签和它的所有子节点。
  • body: 不移除所在的标签,但是移除它的所有子节点。
  • tag: 移除所在的标签,但是不移除它的子节点。
  • all-but-first: 移除所在标签的第一个子节点之外的所有子节点。
  • none : 什么也不做。这个值对动态求值有用。

all-but-first有什么用?它让我们在原型设计的时候,可以保留某些th:remove="all"

  1. <table>
  2. <thead>
  3. <tr>
  4. <th>NAME</th>
  5. <th>PRICE</th>
  6. <th>IN STOCK</th>
  7. <th>COMMENTS</th>
  8. </tr>
  9. </thead>
  10. <tbody th:remove="all-but-first">
  11. <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
  12. <td th:text="${prod.name}">Onions</td>
  13. <td th:text="${prod.price}">2.41</td>
  14. <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  15. <td>
  16. <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
  17. <a href="comments.html"
  18. th:href="@{/product/comments(prodId=${prod.id})}"
  19. th:unless="${#lists.isEmpty(prod.comments)}">view</a>
  20. </td>
  21. </tr>
  22. <tr class="odd">
  23. <td>Blue Lettuce</td>
  24. <td>9.55</td>
  25. <td>no</td>
  26. <td>
  27. <span>0</span> comment/s
  28. </td>
  29. </tr>
  30. <tr>
  31. <td>Mild Cinnamon</td>
  32. <td>1.99</td>
  33. <td>yes</td>
  34. <td>
  35. <span>3</span> comment/s
  36. <a href="comments.html">view</a>
  37. </td>
  38. </tr>
  39. </tbody>
  40. </table>

th:remove属性接受任何的Thymeleaf标准表达式,只要它返回允许的字符串值(alltagbodyall-but-first或者none)。

这意味着可以使用条件表达式,比如:

  1. <a href="/something" th:remove="${condition}? tag : none">Link text not to be removed</a>

注意th:removenull等同于none,所以下面的例子和上面的例子的结果相同:

  1. <a href="/something" th:remove="${condition}? tag">Link text not to be removed</a>

在这种情况下,如果${condition}为false,会返回null,因此什么也不会做。