文档

§模板引擎

§基于 Scala 的类型安全模板引擎

Play 附带了 Twirl,这是一个强大的基于 Scala 的模板引擎,其设计灵感来自 ASP.NET Razor。具体来说,它

 

模板是编译的,因此您将在浏览器中看到任何错误。

§概述

Play Scala 模板是一个简单的文本文件,其中包含少量 Scala 代码块。模板可以生成任何基于文本的格式,例如 HTML、XML 或 CSV。

模板系统的设计旨在让习惯使用 HTML 的人感到舒适,允许前端开发人员轻松地使用模板。

模板被编译成标准的 Scala 函数,遵循简单的命名约定。如果你创建一个名为 views/Application/index.scala.html 的模板文件,它将生成一个名为 views.html.Application.index 的类,该类包含一个 apply() 方法。

例如,以下是一个简单的模板

@(customer: Customer, orders: List[Order])

<h1>Welcome @customer.name!</h1>

<ul>
@for(order <- orders) {
  <li>@order.title</li>
}
</ul>

然后,你可以像正常调用类的方法一样,从任何 Scala 代码中调用它

val content = views.html.Application.index(c, o)

§语法:神奇的‘@’字符

Scala 模板使用 @ 作为唯一的特殊字符。每当遇到此字符时,它就表示动态语句的开始。你不需要显式地关闭代码块 - 动态语句的结束将从你的代码中推断出来

Hello @customer.name!
       ^^^^^^^^^^^^^
       Dynamic code

由于模板引擎通过分析你的代码自动检测代码块的结束,因此此语法只支持简单的语句。如果你想插入多标记语句,请使用括号显式标记它

Hello @(customer.firstName + customer.lastName)!
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                    Dynamic Code

注意: 确保动态语句的关键字和括号之间不要包含空格。

例如,以下代码不起作用

@for (menu <- menuList) { ... }  // Compilation error: '(' expected but ')' found.
    ^

你也可以使用花括号来编写多语句块

Hello @{val name = customer.firstName + customer.lastName; name}!
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                             Dynamic Code

由于 @ 是一个特殊字符,有时你需要对其进行转义。为此,请使用 @@

My email is bob@@example.com

§模板参数

模板就像一个函数,因此它需要参数,这些参数必须在模板文件的顶部声明

@(customer: Customer, orders: List[Order])

你也可以为参数使用默认值

@(title: String = "Home")

甚至可以使用多个参数组

@(title: String)(body: Html)

§模板构造函数

默认情况下,模板被生成为一个静态函数,可以在任何上下文中调用。如果你的模板依赖于组件,例如消息 API,你可能会发现用它需要的组件(和其他模板)注入它更容易,然后你可以将该模板注入到使用它的控制器中。

Twirl 支持为模板声明构造函数,在文件开头使用 @this() 语法,在模板参数之前。构造函数的参数可以与模板参数以相同的方式定义

@this(myComponent: MyComponent)

@(customer: Customer, orders: List[Order])

§迭代

你可以使用 for 关键字,以一种非常标准的方式

<ul>
@for(p <- products) {
  <li>@p.name ([email protected])</li>
}
</ul>

注意: 确保 {for 在同一行,以指示表达式继续到下一行。

§If-块

If-块没什么特别的。只需使用 Scala 的标准 if 语句即可

@if(items.isEmpty) {
  <h1>Nothing to display</h1>
} else {
  <h1>@items.size items!</h1>
}

§声明可重用代码块

您可以创建可重用的代码块

@display(product: Product) = {
  @product.name ([email protected])
}

<ul>
@for(product <- products) {
  @display(product)
}
</ul>

请注意,您还可以声明可重用的纯代码块

@title(text: String) = @{
  text.split(' ').map(_.capitalize).mkString(" ")
}

<h1>@title("hello world")</h1>

注意: 在模板中以这种方式声明代码块有时可能有用,但请记住,模板不是编写复杂逻辑的最佳位置。通常最好将这些代码外化为 Scala 类(如果您愿意,可以将其存储在 views/ 包中)。

按照惯例,以 implicit 开头的名称定义的可重用块将被标记为 implicit

@implicitFieldConstructor = @{ MyFieldConstructor() }

§声明可重用值

您可以使用 defining 助手定义作用域值

@defining(user.firstName + " " + user.lastName) { fullName =>
  <div>Hello @fullName</div>
}

§导入语句

您可以在模板(或子模板)的开头导入任何您想要的内容

@(customer: Customer, orders: List[Order])

@import utils._

...

要进行绝对解析,请在导入语句中使用 root 前缀。

@import _root_.company.product.core._

如果您在所有模板中都需要一些常见的导入,则可以在 build.sbt 中声明。

TwirlKeys.templateImports += "org.abc.backend._"

§注释

您可以在模板中使用 @* *@ 编写服务器端块注释

@*********************
* This is a comment *
*********************@

您可以在第一行添加注释,将模板文档添加到 Scala API 文档中

@*************************************
 * Home page.                        *
 *                                   *
 * @param msg The message to display *
 *************************************@
@(msg: String)

<h1>@msg</h1>

§转义

默认情况下,动态内容部分会根据模板类型(例如 HTML 或 XML)的规则进行转义。如果您想输出原始内容片段,请将其包装在模板内容类型中。

注意: 使用此功能时,请考虑输出原始 HTML 的安全隐患,如果用户有可能控制内容。此技术是跨站点脚本 (XSS) 漏洞的常见原因,如果不谨慎使用,则很危险。

例如,要输出原始 HTML

<p>
  @Html(article.content)
</p>

§字符串插值

模板引擎可以用作 字符串插值器。您基本上用“$”替换“@”

import play.twirl.api.StringInterpolation

val name = "Martin"
val p    = html"<p>Hello $name</p>"

§显示 Scala 类型

Twirl 通常通过调用 Scala 类型的值的 toString 方法来渲染它们。但是,如果值包装在 Option 或集合(SeqArrayTraversableOnce)中,Twirl 会先解开值,然后调用 toString

例如,

<ul>
  <li>@Option("value inside option")</li>
  <li>@List("first", "last")</li>
  <li>@User("Foo", "Bar")</li>
  <li>@List("hello", User("Foo", "Bar"), Option("value inside option"), List("first", "last"))</li>
</ul>

在浏览器中呈现为

下一步:模板的依赖注入


发现本文档中的错误?此页面的源代码可以在这里找到 这里。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。