内联

Python/Java学习交流群:369606713


12.1表达内联

虽然标准方言允许我们使用标记属性来完成几乎所有操作,但在某些情况下我们可能更喜欢将表达式直接编写到HTML文本中。例如,我们可能更喜欢这样写:

<p>Hello, [[${session.user.name}]]!</p>

......而不是这个:

<p>Hello, <span th:text="${session.user.name}">Sebastian</span>!</p>

在Thymeleaf 之间表达[[...]]或被[(...)]认为是内联表达式,在其中我们可以使用任何类型的表达式,这些表达式在一个th:text或th:utext属性中也是有效的。

请注意,虽然[[...]]对应于th:text(即结果将被HTML转义),但[(...)]对应于th:utext并且不会执行任何HTML转义。所以对于一个变量,例如msg = 'This is great!',给定这个片段:

<p>The message is "[(${msg})]"</p>

结果将使这些标签不转义,因此:

<p>The message is "This is <b>great!</b>"</p>

而如果像以下一样逃脱:

<p>The message is "[[${msg}]]"</p>

结果将被HTML转义:

<p>The message is "This is &lt;b&gt;great!&lt;/b&gt;"</p>

请注意,默认情况下,文本内联在标记中的每个标记的主体中都是活动的 - 而不是标记本身 - 因此我们无需执行任何操作即可启用它。

内联vs自然模板

如果你来自其他模板引擎,其中这种输出文本的方式是常态,你可能会问:为什么我们从一开始就不这样做?它的代码少于所有这些 th:text 属性!

好吧,小心那里,因为尽管你可能会发现内联非常有趣,但是你应该永远记住,当你静态打开它们时,内联表达式将逐字显示在你的HTML文件中,所以你可能无法将它们用作设计原型了!

浏览器静态显示我们的代码片段而不使用内联的区别...

Hello, Sebastian!

......并使用它......

Hello, [[${session.user.name}]]!

......在设计实用性方面非常清楚。

禁用内联

但是,可以禁用此机制,因为实际上可能存在我们确实希望输出[[...]]或[(...)]序列而不将其内容作为表达式处理的情况。为此,我们将使用th:inline="none":

<p th:inline="none">A double array looks like this: [[1, 2, 3], [4, 5]]!</p>

这将导致:

<p>A double array looks like this: [[1, 2, 3], [4, 5]]!</p>

12.2文字内联

文本内联与我们刚刚看到的表达内联功能非常相似,但它实际上增加了更多功能。必须明确启用它th:inline="text"。

文本内联不仅允许我们使用我们刚刚看到的相同内联表达式,而且实际上处理标签主体就好像它们是在TEXT模板模式下处理的模板一样,这允许我们执行基于文本的模板逻辑(不仅仅是输出表达式)。

我们将在下一章中看到有关文本模板模式的更多信息。

12.3 JavaScript内联

JavaScript内联允许<script>在HTML模板模式下处理的模板中更好地集成JavaScript 块。

与文本内联一样,这实际上相当于处理脚本内容,就好像它们是JAVASCRIPT模板模式中的模板一样,因此文本模板模式的所有功能(见下一章)都将在眼前。但是,在本节中,我们将重点介绍如何使用它将Thymeleaf表达式的输出添加到JavaScript块中。

必须使用th:inline="javascript"以下方式显式启用此模式:

<script th:inline="javascript">
    ...
    var username = [[${session.user.name}]];
    ...
</script>

这将导致:

<script th:inline="javascript">
    ...
    var username = "Sebastian \"Fruity\" Applejuice";
    ...
</script>

以上代码中需要注意的两件重要事项:

首先,JavaScript内联不仅会输出所需的文本,而且还会用引号和JavaScript来包含它 - 转义其内容,以便将表达式结果输出为格式良好的JavaScript文字。

其次,发生这种情况是因为我们将${session.user.name}表达式输出为转义,即使用双括号表达式:[[${session.user.name}]]。如果相反,我们使用非转义,如:

<script th:inline="javascript">
    ...
    var username = [(${session.user.name})];
    ...
</script>

结果如下:

<script th:inline="javascript">
    ...
    var username = Sebastian "Fruity" Applejuice;
    ...
</script>

...这是一个格式错误的JavaScript代码。但是,如果我们通过附加内联表达式来构建脚本的一部分,那么输出未转义的内容可能就是我们所需要的,因此最好有这个工具。

JavaScript自然模板

所提到的JavaScript内联机制的智能远不止仅仅应用特定于JavaScript的转义并将表达式结果作为有效文字输出。

例如,我们可以在JavaScript注释中包装我们的(转义的)内联表达式,如:

<script th:inline="javascript">
    ...
    var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit";
    ...
</script>

并且Thymeleaf将忽略我们在注释之后和分号之前(在这种情况下'Gertrud Kiwifruit')编写的所有内容,因此执行此操作的结果将与我们不使用包装注释时完全相同:

<script th:inline="javascript">
    ...
    var username = "Sebastian \"Fruity\" Applejuice";
    ...
</script>

但请仔细查看原始模板代码:

<script th:inline="javascript">
    ...
    var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit";
    ...
</script>

请注意这是有效的JavaScript代码。当您以静态方式打开模板文件时(无需在服务器上执行),它将完美执行。

所以我们这里有一个做自然模板的方法!

高级内联评估和JavaScript序列化

关于JavaScript内联的一个重要注意事项是,这种表达式评估是智能的,不仅限于字符串。Thymeleaf将在JavaScript语法中正确编写以下类型的对象:

  • Strings
  • Numbers
  • Booleans
  • Arrays
  • Collections
  • Maps
  • Beans (objects with getter and setter methods)

例如,如果我们有以下代码:

<script th:inline="javascript">
    ...
    var user = /*[[${session.user}]]*/ null;
    ...
</script>

该${session.user}表达式将评估为一个User对象,Thymeleaf将正确地将其转换为Javascript语法:

<script th:inline="javascript">
    ...
    var user = {"age":null,"firstName":"John","lastName":"Apricot",
                "name":"John Apricot","nationality":"Antarctica"};
    ...
</script>

这种JavaScript序列化的方式是通过org.thymeleaf.standard.serializer.IStandardJavaScriptSerializer接口的实现,可以StandardDialect在模板引擎使用的实例上配置。

此JS序列化机制的默认实现将在类路径中查找Jackson库,如果存在,将使用它。如果没有,它将应用内置的序列化机制,涵盖大多数场景的需求并产生类似的结果(但不太灵活)。

12.4 CSS内联

Thymeleaf还允许在CSS <style>标签中使用内联,例如:

<style th:inline="css">
  ...
</style>

例如,假设我们将两个变量设置为两个不同的String值:

classname = 'main elems' align = 'center' 我们可以像以下一样使用它们:

<style th:inline="css">
    .[[${classname}]] {
      text-align: [[${align}]];
    }
</style>

结果将是:

<style th:inline="css">
    .main\ elems {
      text-align: center;
    }
</style>

请注意CSS内联如何具有一些智能,就像JavaScript一样。具体来说,通过转义表达式输出的表达式[[${classname}]]将作为CSS标识符进行转义。这就是为什么我们classname = 'main elems'已经main\ elems在上面的代码片段中变成了原因。

高级功能:CSS自然模板等

与之前针对JavaScript解释的内容相同,CSS内联还允许我们的<style>标记静态和动态地工作,即通过在注释中包装内联表达式作为CSS自然模板。看到:

<style th:inline="css">
    .main\ elems {
      text-align: /*[[${align}]]*/ left;
    }
</style>