一个基于Scala的类型安全的模版引擎
Play2.0带来了一个全新的真正强大的基于Scala的模版引擎。该引擎的设计灵感源于ASP.NET Razor.特别是:
简洁,富有表达力,流畅:最小化语法字符和击键要求,让你快速,流畅的编写代码。不像大多数模版引擎的语法,你无须明确的中断HTML代码就可嵌入服务器端逻辑。引擎会智能 的为你识别。这是一个真正简洁,富有表达力的语语法,使输入变得干净,快速,愉快。
易于学习:掌握简单的概念就能让你快速产出。它使用你已掌握的Scala和HTML技能。
非新语言:我们极力避免创造一门新语言。相反,我们想使开发人员能够利用其现有的Scala语言技能,在你选择的语言下提供一个HTML结构工作流程的模板标记语法。
可使用任何文本编辑器:不需要特别的编辑工具,旧的文本编辑器也可轻松工作。
模版会被编译,因此你可以在浏览器中看到任何编译错误。
概述
Play Scala 模版是简单的文本文件,它包含简短的Scala代码块。它可以生成任何的文本格式,HTML,XML,CVS。
模版系统已被设计成可以自然舒适的处理HTML,使得web设计师们能轻松的工作。
模版会被编译成标准的Scala函数,遵循简单的命名约定:如果你创建了一个 views/Application/index.scala.html 模版文件,它將产生一个 views.html.Application.index 函数。
例如,下面这个简单的模版:
@(customer: Customer, orders: Seq[Order])
<h1>Welcome @customer.name!</h1>
<ul>
@orders.map { order =>
<li>@order.title</li>
}
</ul>
你可以在你的任何Scala代码中,像函数一样调用它:
val html = views.html.Application.index(customer, orders)
语法:充满魔力的‘@’字符
Scala模版使用 @ 作为单独,特殊的字符。每当遇到该字符,便是指示这是Scala代码块的开始。不需要明确的关闭该代码块 - 模版会根据代码自动推断:
Hello @customer.name!
^^^^^^^^^^^^^
Scala code
因为模版引擎通过分析源码自动检测代码块结尾处,所以它仅仅支持简单的声明块。如果你想插入多块声明,请明确的用括号标记:
Hello @(customer.firstName + customer.lastName)!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Scala Code
你也可以使用纯正的Scala语法,使用大括号标记多块声明:
Hello @{val name = customer.firstName + customer.lastName; name}!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Scala Code
由于 @ 是特殊字符,有时候你需要转义。像这样 @@ :
My email is bob@@example.com
模版参数
模版是一个普通函数,所以它需要参数,参数必须声明在模版文件的第一行:
@(customer: models.Customer, orders: Seq[models.Order])
你也可以指定参数默认值:
@(title: String = "Home")
或者甚至是参数组:
@(title:String)(body: => Html)
甚至一个隐式参数:
@(title: String)(body: => Html)(implicit request: play.api.mvc.Request)
迭代
你可以使用 Scala 的for-comprehension,以很表标的方式。但注意,编译器会自动在你的代码块前面加上 yield 关键字:
<ul>
@for(p <- products) {
<li>@p.name ($@p.price)</li>
}
</ul>
你可能意识到了,该for仅仅是经典的map形式的语法糖:
<ul>
@products.map { p =>
<li>@p.name ($@p.price)</li>
}
</ul>
if块
if块也没什么特别。简单的使用标准的 Scala if 声明:
@if(items.isEmpty) {
<h1>Nothing to display</h1>
} else {
<h1>@items.size items!</h1>
}
模式匹配
你也可以在模版中使用模式匹配:
@connected match {
case models.Admin(name) => {
<span class="admin">Connected as admin (@name)</span>
}
case models.User(name) => {
<span>Connected as @name</span>
}
}
定义可重用块
你可以定义可重用代码块:
@display(product: models.Product) = {
@product.name ($@product.price)
}
<ul>
@products.map { p =>
@display(product = p)
}
</ul>
注意你也可以用纯Scala方式声明可重用代码块:
@title(text: String) = @{
text.split(' ').map(_.capitalize).mkString(" ")
}
<h1>@title("hello world")</h1>
注意:这种方式声明的代码块某些时候可能很有用,但谨记,模块不是一个编写复杂逻辑的好地方。它通常都应该提取到外部的Scala文件中。(如果你愿意,出可以保存在views/目录中)
依照惯例,以 implicit 开头的可重用块会被标记为 隐式的:
@implicitFieldConstructor = @{ MyFieldConstructor() }
声明可重用值
你可以使用 define 定义范围变量值:
@defining(user.firstName + " " + user.lastName) { fullName =>
<div>Hello @fullName</div>
}
导入声明
你可以在模版开头(或子模块)处按需导入声明:
@(customer: models.Customer, orders: Seq[models.Order])
@import utils._
...
注释
在服务器端编写注释,你可以使用 @* *@:
@*********************
* This is a comment *
*********************@
你可以在第一行编写注释以Scala API的形式文档化该模版。
@*************************************
* Home page. *
* *
* @param msg The message to display *
*************************************@
@(msg: String)
<h1>@msg</h1>
转义
默认情况下,内容的动态部分会依照模版的类型转义(如 HTML,XML)。如果你需要输出原生的内容,请在模版中用模版内容类型包装。
如输出原始的HTML
<p>
@Html(article.content)
</p>
Scala模版的常见用例
模版,作为普通函数,可通过任何方式组合。下面是一些常用的场景例子。
布局
让我们声明一个 views/main.scala.html 模版,它將作为主要布局模版:
@(title: String)(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
</head>
<body>
<section class="content">@content</section>
</body>
</html>
你看到,该模版需要两个参数:title 和 Html 内容块。我们可以在另一个 views/Application/index.scala.html 中使用它:
@main(title = "Home") {
<h1>Home page</h1>
}
注意:我们有时命名参数为@main(title = "Home"),有时候为@main("Home")。依你所好,在不同的场景中选择更简洁的形式。
有时候,你需要另一个页面特定的内容,例如边栏或者页脚。你可以指定另一个参数:
@(title: String)(sidebar: Html)(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
</head>
<body>
<section class="sidebar">@sidebar</section>
<section class="content">@content</section>
</body>
</html>
在我们的'index'模版中使用它,需要:
@main("Home") {
<h1>Sidebar</h1>
} {
<h1>Home page</h1>
}
另外,我们可以单独声明边栏:
@sidebar = {
<h1>Sidebar</h1>
}
@main("Home")(sidebar) {
<h1>Home page</h1>
}
标签(它们也不过是函数,不是吗?)
让我们编写一个简单的 views/tags/notice.scala.html 标签,显示HTML通知:
现在,让我们在另一个模版中使用它:
@(level: String = "error")(body: (String) => Html)
@level match {
case "success" => {
<p class="success">
@body("green")
</p>
}
case "warning" => {
<p class="warning">
@body("orange")
</p>
}
case "error" => {
<p class="error">
@body("red")
</p>
}
}
包含
同样,这也没什么特别。你可以调用任何你需要的模版(实际上是来自任何地方的函数都可以):
<h1>Home</h1>
<div id="side">
@common.sideBar()
</div>