Thymeleaf 教程

引用模板片段

定义和引用片段

在我们的模板中,我们经常希望包含其他模板的部分内容,如:页脚、页眉、菜单...等等。

为了做到这一点,Thymeleaf 需要我们定义这些部分模板(即模板 “片段”),以便其他模板引用。Thymeleaf 可以通过 th:fragment 属性来实现片段定义。

假设我们想给所有的杂货店页面添加一个标准的版权页脚,那么我们就创建一个 /WEB-INF/templates/footer.html 文件,其中包含以下代码。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <body>
    <div th:fragment="copy">
      &copy; 2011 The Good Thymes Virtual Grocery
    </div>
  </body>
</html>

上面的代码定义了一个名为 “copy” 的片段,我们可以使用 th:insert th:replace 属性(也可以使用 th:include 属性,不过从 Thymeleaf 3.0 开始不再推荐使用该属性)轻松地将其纳入我们的主页模板。代码如下:

<body>
  ...
  <div th:insert="~{footer :: copy}"></div>
</body>

注意,th:insert 属性期望一个片段表达式(~{...}),它是一个能生成片段的表达式。不过在上面的例子中,这是一个非复杂的片段表达式,使用 “~{” 和符号 “}” 包围片段名是完全可选的,所以上面的代码将等同于下面代码:

<body>
  ...
  <div th:insert="footer :: copy"></div>
</body>

注意:如果在 /view/footer.html 页面定义了片段 copy,那么在页面 /home.html 或 /view/home.html 中需要使用 th:insert="~{view/footer :: copy}" 或者 th:insert="view/footer :: copy"。

片段规范语法

片段表达式的语法非常简单明了。有三种不同的格式。

(1)“~{templename :: selector}” 表达式将包含在名为 templename 的模板上使用 th:fragment 属性定义的名为 selector 的片段。注意,selector 可以只是一个片断名称,因此您可以指定类似于上面的 ~{footer :: copy} 这样简单的名称,如:~{templatename :: fragmentname}。

(2)“~{templatename}” 表达式可以仅仅包括名为 templatename 的完整模板,整个模板 body 标签内部的元素全部引用过来。

(3)“~{::selector}” 或 “~{this::selector}” 从同一模板插入匹配 selector 的片段。如果在出现片段表达式的模板上匹配不到 selector,模板调用堆栈将向最初处理的模板(根)遍历,直到选择器在某个级别匹配。例如:

fragment3.html 内容如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org/">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf模板引擎</title>
</head>
<body>

<div style="display:none;">
    <!-- 定义一个名为 myCopy 的片段 -->
<div th:fragment="myCopy">
<p>Copyright ©2022 版权信息</p>
</div>
</div>

<!-- 引用一个完整的模板 -->
<div th:insert="~{view/public3 :: copy}">Copyright Info</div>

</body>
</html>

public3.html 内容如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org/">
<body>

<div th:fragment="copy">
    <!-- 引用了一个当前模板文件没有定义的片段,但是在父模板 fragment3.html 中定义了它 -->
    <div th:insert="~{this :: myCopy}">MyCopy Info</div>
</div>

</body>
</html>

注意,上述示例中的 templatename 和 selector 都可以是功能齐全的表达式(甚至是条件表达式),如:

<div th:insert="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>

再次提示,片段表达式两边的花括号 “~{…}” 在 th:insert 或 th:replace 属性中是可选的。

片段可以包含任何 th:* 属性。一旦片段被包含到目标模板(具有 th:insert / th:replace 属性的模板)中,这些属性将被求值,并且它们将能够引用此目标模板中定义的任何上下文变量。

引用不带 th:fragment 属性的片段

由于标记选择器的强大功能,我们可以包含不使用任何 th:fragment 属性的片段。它甚至可以是来自完全不了解 Thymeleaf 的不同应用程序的标记代码:

...
<div id="copy-section">
  &copy; 2011 The Good Thymes Virtual Grocery
</div>
...

我们可以使用上面的片段,只需通过其 id 属性引用它,引用方法与 CSS 选择器类似:

<body>
  ...
  <div th:insert="~{footer :: #copy-section}"></div>
</body>

th:insert 和 th:replace(和 th:include)之间的差异

th:insert 和 th:replace(以及 th:include,自 Thymeleaf 3.0 以来不推荐)属性之间有什么区别?

  • th:insert 是最简单的,它将简单地插入指定的片段作为其主标记的主体(保留主标记)。

  • th:replace 实际上用指定的片段替换其主标记。

  • th:include 类似于 th:insert,但它只插入该片段的内容,而不是插入片段标签。

因此,HTML片段如下:

<footer th:fragment="copy">
  &copy; 2011 The Good Thymes Virtual Grocery
</footer>

在模板中分别使用 th:insert、th:replace 和 th:include 属性引用片段,如下所示:

<body>
  ...
  <div th:insert="footer :: copy"></div>
  <div th:replace="footer :: copy"></div>
  <div th:include="footer :: copy"></div>
</body>

引擎渲染后,输出结果:

<body>
  ...
  <div>
    <footer>
      &copy; 2011 The Good Thymes Virtual Grocery
    </footer>
  </div>

  <footer>
    &copy; 2011 The Good Thymes Virtual Grocery
  </footer>

  <div>
    &copy; 2011 The Good Thymes Virtual Grocery
  </div>
</body>
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号