play框架06--模板語法、模板繼承
Play具有高效的模板體系,採用Groovy作為其表示式語言,允許動態生成HTML、XML、JSON或者任何基於文字格式的文件,並且具有建立可重用標籤(tag)的功能。模板儲存在Play應用的app/views目錄下。
1、模板語法
與其他的語言一樣,Play的模板也具有嚴格定義的語法。模板語法被劃分為多種元素,用於完成不同型別的任務。Play模板的本質是普通的文字檔案,其中帶有佔位符的部分可以生成動態內容。模板的動態部分採用Groovy語言編寫,其語法與Java非常類似。框架可以將需要渲染的結果追加至HTTP響應的資料部分,併發送至模板。所有的動態部分將會在模板的執行期間被解析。
(表1 模板語法)
元素 | 描述 | 語法 |
---|---|---|
表示式 | 用於輸出表達式的值。如 ${note.title} 的作用是將域物件note的屬性title的值輸出。 | ${...} |
標籤 | 用於呼叫Play框架內建的或是開發人員自定義的標籤。如#{get 'title' /}:獲取變數 title 的值,該值僅在模板頁面中有效。 | #{...} |
引用 | 用於生成呼叫控制器中Action方法的URL,在頁面連結中使用的最為頻繁。@{...} 和 @@{...} 的區別在於生成的URL分別是相對路徑還是絕對路徑。如: 1.<a href="@{Application.index()}">首頁</a>:生成指向首頁的連結。 |
@{...} 和@@{...} |
國際化 | 用於顯示經過國際化處理後的訊息內容。 | &{...} |
註釋 | 用於在模板中添加註釋。如:*{ 這是註釋 }*。 | *{...}* |
指令碼 | 用於新增複雜的 Groovy 指令碼,可以宣告變數和執行業務邏輯。 | %{...}% |
1.1 表示式(expression):${…}
構建動態部分最簡單的方法就是宣告表示式。表示式需要以 ${ 開頭, 並以 } 結尾,作為佔位符使用。具體例子如下:
<h1>Client ${client.name}</h1>以上是輸出客戶姓名的表示式例子。在該例子中,將客戶類定義為Client。經過控制器中Action的業務邏輯執行,首先需要向模板注入物件client,之後就可以在模板中使用${…}表示式語法輸出client物件的name屬性。
如果不能確定向模板注入的client物件是否為null,可以使用如下Groovy快捷語法:
<h1>Client ${client?.name}</h1>此時,只有client不為null的情況下,才進行client.name的輸出。
1.2 標籤(tag): #{tagName /}#
標籤是能夠附帶引數呼叫的模板片段,如果標籤只有一個引數,按照約定,引數的名稱為arg,並且該引數名是可以省略的。例如,可以使用#{script}標籤載入JavaScript檔案:#{script 'jquery.js' /}
Play模板中的標籤必須是閉合的,可以通過兩種方式閉合標籤。採用直接閉合的形式:
#{script 'jquery.js'/}
或者起始標籤和結束標籤成對地使用:
#{script 'jquery.js'}#{/script}
#{script}是Play模板的內建標籤,由框架實現,可以直接使用。後面會進一步介紹如何自定義標籤來滿足開發中一些特定的需求。#{list}標籤可以對集合類進行迭代操作,使用時需要注意,必須帶有兩個引數(items以及as):
<h1>Client ${client.name}</h1>上例中使用#{list}標籤對client.accounts集合進行迭代,並將集合中的每一條資料作為account在頁面中輸出。
<ul>
#{list items:client.accounts, as:'account' }
<li>${account}</li>
#{/list}
</ul>
在應用中,模板引擎預設對所有的動態表示式進行轉義,以此來避免XSS的安全問題。如果模板中變數${title}的內容為<h1>Title</h1>,在頁面輸出時會自動進行轉義:
${title} --> <h1>Title</h1>
也可以通過呼叫擴充套件方法raw(),以非轉義的形式在頁面中輸出,具體使用方法如下:
${title.raw()} --> <h1>Title</h1>
如果需要顯示大量的非轉義HTML內容,可以使用#{verbatim /}標籤:
#{verbatim}
${title} --> <h1>Title</h1>
#{/verbatim}
1.3 引用(action):@{…}或者@@{…}#
在前面的章節已經有過一些介紹,Play通過路由器可以(逆向)生成URL,匹配指定的路由。在模板中使用@{…}引用可以達到相同的目的:
<h1>Client ${client.name}</h1>該例項中,@{Clients.showAccounts(client.id)}呼叫了Clients控制器中的showAccounts Action方法,並傳遞了client.id引數。
<p>
<a href="@{Clients.showAccounts(client.id)}">All accounts</a>
</p>
<hr />
<a href="@{Clients.index()}">Back</a>
@@{…}引用的使用語法與@{…}相同,只不過生成的是絕對URL(尤其適用於郵箱)。
1.4 國際化(messages):&{…}#
如果應用需要進行國際化操作,那麼可以在模板中使用&{...}顯示國際化資訊。需要進行國際化的應用首先需要在conf/messages檔案中進行國際化定義:
clientName=The client name is %s
之後在模板中就可以通過&{...}顯示該國際化資訊了:
<h1>&{'clientName',client.name}</h1>
1.5 註釋(comment):*{…}*#
使用*{…}*標記的內容會被模板引擎忽略,起到註釋作用:*{**** Display the user name ****}*
<div class="name">
${user.name}
</div>
1.6 指令碼(script): %{…}%#
指令碼是更加複雜的表示式集合,能夠宣告一些變數或者定義一些語句。Play的模板中使用%{…}%插入指令碼:%{
fullName = client.name.toUpperCase()+' '+client.forname;
}%
<h1>Client ${fullName}</h1>
也可以直接使用out內建物件輸出動態內容:
%{
fullName = client.name.toUpperCase()+' '+client.forname;
out.print('<h1>'+fullName+'</h1>');
}%
在模板中還可以使用指令碼編寫結構化語句,執行一些邏輯操作,比如迭代:
<h1>Client ${client.name}</h1>
<ul>
%{
for(account in client.accounts) {
}%
<li>${account}</li>
%{
}
}%
</ul>
使用模板時切記:模板不適合處理複雜的業務邏輯,所以在模板中請儘量使用標籤,或者直接將處理交給控制器或模型物件。
2、模板繼承
Play提供繼承機制為多模板之間進行頁面佈局或設計提供服務。#{extends /} 和 #{doLayout /}可以使頁面的共享和重用變得更加方便簡潔,同時也能夠幫助開發人員實現頁面中動態內容和靜態外觀裝飾的分離。在模板與裝飾之間可以使用#{get}和#{set}標籤進行引數傳遞。
將simpledesign.html定義為父模板,也就是裝飾模板。可以將頁面中重用的靜態內容定義在裝飾模板中,如導航條、頁面頂端的圖片banner、頁面底端的footer說明等。
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">在simpledesign.html中將<head></head>、<h1></h1>、<div class="footer"></div>中的內容定義為公用元素,所有繼承於該模板的頁面都會包含這些內容。其中#{doLayout /}標籤起到佔位的作用,包含其子模板的頁面內容。其他所有繼承於simpledesign.html模板的頁面內容都將顯示在#{doLayout /}所佔的頁面區塊。
<head>
<title>#{get 'title' /}</title>
<link rel="stylesheet" type="text/css" href="@{'/public/stylesheets/main.css'}" />
</head>
<body>
<h1>#{get 'title' /}</h1>
#{doLayout /}
<div class="footer">Built with the play! framework</div>
</body>
</html>
其他頁面使用#{extends}標籤可以非常簡單地植入該裝飾模板,具體使用方法如下:
#{extends 'simpledesign.html' /}該子模板使用#{extends 'simpledesign.html' /}標籤來繼承simpledesign.html,使用#{set title:'A decorated page' /}標籤傳遞頁面的title變數,最後在頁面中輸出This content will be decorated。
#{set title:'A decorated page' /}
This content will be decorated.