freemarker實現通用布局的模板拆分與復用
原文:http://www.hawu.me/coding/733
一、基礎頁面布局
假設我們項目頁面的通用布局如下圖所示:
實現這樣的布局的基本html代碼如下:
XHTML1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<html>
<head>
</head>
<body>
<div style="width: 700px; text-align:center; font-size:30px;">
<div style="">header</div> |
這樣看起來很簡潔是吧,但實際上一個頁面的代碼是很淩亂的。如果我們每個前端頁面都是基於這個布局,只是main content的內容有所不同。那麽從模板的可復用角度來考慮,我們就應該header、siderbar、fotter作為單獨的模板剝離出來。然後在渲染main content頁面時候加載這些通用的模板。
二、freemarker基礎語法
2.1 插值 ${…}
freemarker會將花括號內表達式的計算結果替換到這個花括號的位置${…}。比如
1 2 | <b>hello, ${user.name}</b> 5 + 2 = ${5+2} |
那麽這個模板在freemarker處理後會輸出(假定user.name=”funway”)
1 2 | <b>hello, funway</b> 5 + 2 = 7 |
2.2 <#…>與<@…>
<#…>表示freemarker內建的指令,比如<#macro>、<#if>、<#list>、<#assign>。
<@…>表示用戶自定義的指令,自定義指令要先用<#macro>宏來定義。(參見2.4)
2.3 <#include>與<#import>
include指令表示在當前位置插入其他文件的內容。比如<#include “/copyright.html”>
import指令表示將一個文件作為一個命名空間引入到當前文件。標準寫法是<#import “filePath” as nameSpace>。就像java的命名空間一樣,防止兩個文件中相同的變量名或者自定義指令名沖突。然後就可以在當前模板中使用${nameSpace.variable}和<@nameSpace.command>來調用該命名空間的變量與指令了。
include引入文件的內容(包括其中自定義的變量與指令),但import只會引入變量與指令,不會把html寫入。
2.4 <#macro>
參考官方文檔
macro宏用來定義自定義指令。基本語法是
name 表示自定義的指令名
param 可選,表示指令參數
nested 可選,表示嵌套內容
return 可選,表示到這就結束了,後面代碼不執行了
2.4.1 簡單的macro
1 2 3 4 5 6 7 | <#-- 用macro定義一個sayHello指令 --> <#macro sayHello> <b>hello, world</b> </#macro> <#-- 調用上面定義的sayHello指令 --> <@sayHello/> |
上面這段模板輸出的html文本如下:
1 | <b>hello, world</b> |
2.4.2 帶參數的macro
1 2 3 4 5 6 7 | <#-- 用macro定義一個帶參的sayHelloTo指令 --> <#macro sayHelloTo person> hello, <b>${person}</b> </#macro> <#-- 調用上面定義的帶參sayHelloTo指令 --> <@sayHelloTo person="funway"/> |
這個模板的輸出結果如下:
1 | hello, <b>funway</b> |
2.4.3 嵌套內容
1 2 3 4 5 6 7 8 9 10 11 12 13 | <#macro sayHello> hello, world. <br/> <#-- 在這裏嵌入指令調用時候要嵌套的內容 --> <#nested> <br/> form: funway </#macro> <@sayHello> <#-- 這裏寫上需要嵌套的內容 --> this is nested content. </@sayHello> |
這段模板的輸出如下:
1 2 3 4 5 | hello, world. <br/> this is nested content. <br/> form: funway |
三、布局模板拆分
使用freemarker的macro、import、include指令,我們可以將布局模板拆分為如下幾個文件
defaultLayout.ftl XHTML1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <#macro layout> <html> <head> </head> <body> <div style="width: 700px; text-align:center; font-size:30px;"> <#include "header.ftl"> <#include "sidebar.ftl"> <#-- 在這裏嵌入main content --> <#nested> <#include "footer.ftl"> </div> </body> </html> </#macro> |
header.ftl XHTML
1 | <div style="">header</div> |
sidebar.ftl XHTML
1 2 3 | <div style="width:30%; height:300px; float:left; "> sidebar </div> |
footer.ftl XHTML
1 | <div style="">fotter</div> |
那麽在任何一個使用該布局的頁面,我們只要寫如下的代碼,修改要嵌入到layout中的main content就好了。
page.ftl XHTML1 2 3 4 5 6 7 8 9 10 11 | <#-- 引入布局指令的命名空間 --> <#import "../layout/defaultLayout.ftl" as defaultLayout> <#-- 調用布局指令 --> <@defaultLayout.layout> <#-- 將下面這個main content嵌入到layout指令的nested塊中 --> <div style="width:70%; height:300px; float:left; "> main content</div> </@defaultLayout.layout> |
而且如果要更換布局,比如修改header,也不用每個頁面都去改一遍了。這就實現了模板的可復用。
四、題外話,關於freemarker的一些小細節
4.1 判斷變量是否存在或者為null
freemarker不允許在模板中調用一個不存在或者為null的變量,否則會直接出錯退出。所以在輸出一個變量之前盡量先判斷該變量是否存在:
freemarker實現通用布局的模板拆分與復用