原文:http://www.hawu.me/coding/733
一、基礎頁面布局
假設我們項目頁面的通用布局如下圖所示:
實現這樣的布局的基本html代碼如下:
1
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>
<div style="width:30%; height:300px; float:left; ">
sidebar</div>
<div style="width:70%; height:300px; float:left; ">
main content</div>
<div style="">fotter</div>
</div>
</body>
</html>
|
這樣看起來很簡潔是吧,但實際上一個頁面的代碼是很凌亂的。如果我們每個前端頁面都是基於這個布局,只是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指令,我們可以將布局模板拆分為如下幾個文件
1
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>
|
1
|
<div style="">header</div>
|
1
2
3
|
<div style="width:30%; height:300px; float:left; ">
sidebar
</div>
|
1
|
<div style="">fotter</div>
|
那么在任何一個使用該布局的頁面,我們只要寫如下的代碼,修改要嵌入到layout中的main content就好了。
1
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的變量,否則會直接出錯退出。所以在輸出一個變量之前盡量先判斷該變量是否存在: