到目前为止,我们已经用通常的方式为我们的杂货店制作了模板,并以属性的形式将逻辑插入我们的模板中。
但 Thymeleaf 还允许我们将模板标记与逻辑完全分离,允许在 HTML 和 XML 模板模式下创建完全无逻辑的标记模板。
主要的想法是,模板逻辑将被定义在一个单独的逻辑文件中(更确切地说,是逻辑资源,因为它不一定必须是一个文件)。默认情况下,该逻辑资源将是一个额外的文件,与模板文件放在在同一个地方(如文件夹),名称相同,但扩展名为 .th.xml。
/templates
+->/home.html
+->/home.th.xml
因此,home.html 文件可以是完全没有逻辑的。它可能看起来像这样:
<!DOCTYPE html> <html> <body> <table id="usersTable"> <tr> <td class="username">Jeremy Grapefruit</td> <td class="usertype">Normal User</td> </tr> <tr> <td class="username">Alice Watermelon</td> <td class="usertype">Administrator</td> </tr> </table> </body> </html>
上面代码中,绝对没有 Thymeleaf 的代码。这是一个单纯的模板文件,一个没有 Thymeleaf 或模板知识的文件,设计师可以对它进行创建、编辑。或者是由一些外部系统提供的 HTML 片段,根本没有 Thymeleaf 的代码。
现在,让我们通过创建额外的 home.th.xml 文件,把 home.html 模板变成 Thymeleaf 模板,像这样:
<?xml version="1.0"?> <thlogic> <attr sel="#usersTable" th:remove="all-but-first"> <attr sel="/tr[0]" th:each="user : ${users}"> <attr sel="td.username" th:text="${user.name}" /> <attr sel="td.usertype" th:text="#{|user.type.${user.type}|}" /> </attr> </attr> </thlogic>
在这里,我们可以看到在一个 <thlogic> 标签内有很多 <attr> 标签。这些 <attr> 标签对原始模板的节点进行属性注入,它们通过自身的 sel 属性来选择目标标签,这些属性包含 Thymeleaf 标记选择器(实际上是 AttoParser 标记选择器)。
还要注意的是,<attr> 标签可以被嵌套,以便它们的选择器被附加。例如,上面的 sel="/tr[0]",将被处理为 sel="#usersTable/tr[0]"。而用户名 <td> 的选择器将被处理为 sel="#usersTable/tr[0]/td.username"。
所以,一旦将上面的 home.html 和 home.th.xml 文件进行合并,效果和下面文件一致:
<!DOCTYPE html> <html> <body> <table id="usersTable" th:remove="all-but-first"> <tr th:each="user : ${users}"> <td class="username" th:text="${user.name}">Jeremy Grapefruit</td> <td class="usertype" th:text="#{|user.type.${user.type}|}">Normal User</td> </tr> <tr> <td class="username">Alice Watermelon</td> <td class="usertype">Administrator</td> </tr> </table> </body> </html>
这看起来更熟悉,而且确实比创建两个单独的文件要省事。但解耦模板的好处是,我们可以为我们的模板赋予完全独立于 Thymeleaf 的特性,因此从设计的角度来看,可维护性更好。
当然,设计者或开发者之间仍然需要一些契约 —— 例如,用户 <table> 需要一个 id="usersTable" —— 但在很多情况下,纯 HTML 模板将是设计和开发团队之间更好的沟通工具。