在前端页面中,总是出现需要遍历集合中的元素以展示所有信息的场景。Thymeleaf标准方言为我们提供了一个有用的属性:th:each。
用法
假设后台控制器添加了一个商品列表的属性 prods。然后,我们使用 th:each 在模板中使用来遍历产品列表:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<h1>Product list</h1>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
</table>
<p>
<a href="../home.html" th:href="@{/}">Return to home</a>
</p>
</body>
</html>
prod : ${prods} 属性的含义为:循环 ${prods} 属性的每一个元素。${prods} 为被迭代变量,prod 为迭代变量,即当前循环的元素。
需要注意的是,prod 为迭代变量的作用域为 <tr> 元素,可用于其内部标记 <td>。
可迭代对象
java.util.List 类并不是Thymeleaf中唯一的可被用于迭代的对象。还有一些其它的可被迭代的集合对象:
- 任何实现于 java.util.Iterable 的对象
- 任何实现于 java.util.Enumeration 的对象
- 任何实现于 java.util.Iterator 的对象,其值将由迭代器返回,而无需在内存中缓存
- 任何实现于 java.util.Map 的对象,当迭代 Map 对象时,迭代对象则是 java.util.Map.Entry 类
- 任何数组
- 任何包含其对象本身的单值列表
迭代状态
在使用 th:each 时,Thymeleaf提供了一种用于跟踪迭代状态的有用机制:状态变量。
状态变量在 th:each 属性中定义,并且包含以下数据:
- index 属性,当前的迭代索引,从0开始。
- count 属性,从1开始的当前迭代索引。
- size 属性,迭代变量中元素的总数。
- current 属性,每次迭代的变量。
- even/odd 布尔属性,当前迭代是偶数还是奇数。
- first 布尔属性,当前迭代是否是第一个。
- last 布尔属性,当前迭代是否为最后一个。
示例:
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
</table>
状态变量(本例中为 iterStat)通过在 th:each 属性中迭代变量后写入名称,并以逗号分隔。同样的,其作用域与定义 th:each 属性的代码片段一致。
如果未明确设置状态变量,则Thymeleaf将始终通过在迭代变量名后添加 Stat 后缀来创建:
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
</table>
惰性加载
有时候我们想优化数据的检索方式,比如在真正用到这些数据时才检索。
实际上,这可以应用于任何数据,但是考虑到内存中集合可能具有的大小,对于这种情况,检索要迭代的集合是最常见的情况。
为了支持这一特性,Thymeleaf提供了一种延迟加载上下文变量的机制。实现 ILazyContextVariable 接口的上下文变量(很可能是通过扩展其 LazyContextVariable 默认实现)将在执行时解析。例如:
model.addAttribute(
"users",
new LazyContextVariable<List<User>>() {
@Override
protected List<User> loadValue() {
return databaseRepository.findAllUsers();
}
});
可以在不了解其惰性加载特性的情况下使用此变量,例如:
<ul>
<li th:each="u : ${users}" th:text="${u.name}">user name</li>
</ul>
但是同时, 如果在以下代码中 condition 计算为 false,则将永远不会初始化(loadValue()方法永远不会调用):
<ul th:if="${condition}">
<li th:each="u : ${users}" th:text="${u.name}">user name</li>
</ul>
我是银河架构师,十年饮冰,难凉热血,愿历尽千帆,归来仍是少年!
如果文章对您有帮助,请举起您的小手,轻轻【三连】,这将是笔者持续创作的动力源泉。当然,如果文章有错误,或者您有任何的意见或建议,请留言。感谢您的阅读!
文章不定时更新,可微信搜索「银河架构师」,精彩内容,先睹为快!