text/template, html/template 使用
最主要 text/template 是核心的模板功能,只輸出傳文字的功能,而 html/template 是基於 text/template 的功能之上開發的模組, 像是 html/template 會自動在輸出時先把文字載入脫曳字元,也包含許多預設的方法。詳情可以參考: https://golang.org/pkg/html/template/
結構
template 使用上,是先做 ParseFiles, ParseGlob 之類的行為,來讀取檔案,再透過 Execute, ExecuteTemplate 之類的方法來把模板回傳到 response 。基本的渲染程式如下:
func main() {
// select the file want to parse.
tpl, err := template.ParseFiles("index.html")
//execute printout to stdout or response.
err := tpl.Execute(os.Stdout, nil)
if err != nil {
panic(err)
}
}
模板路徑
以下介紹兩種分別為 ParseFiles 和 ParseGlob 的讀取模板檔案的方式。用 ParseFiles 讀取模板, 方法是這樣寫的:
tpl, err := template.ParseFiles("index.html", "./widget/widget-1.html", "widget-2.html") //(...)
其中 ParseFiles 的模組參數,是寫 ... ,所以你可以丟入所有模板的路徑,不過也只能丟固定檔案名稱。而 ParseGlob 是可以用 Patterns 的模式,來抓到所有符合條件的檔案,它是這樣寫的:
tpl, err := template.ParseGlob("./*.html")
而這樣寫之後只要該目錄符合 .html 的副檔名,就會被讀進去。Must
template.Must 可以幫你檢查模板使用是否有錯誤,然後再回傳單一一個 template 的類型,官方的模組是這樣寫的:func Must(t *Template, err error) *Template {
if err != nil {
panic(err)
}
return t
}
所以執行後,不需要再用 err 接收。實際用法是這樣:
tpl := template.Must(template.New("").ParseGlob("./*.html"))
Execute 與提取變數到 Template
將變數丟到 Template,需要將變數作為參數放在 Execute 類的方法中,變數可以接受任何的值, struct, slice, value 之類,但是只能加一個參數進去。程式寫法如下:
//如果你是使用 ParseGlob 來解析檔案,記得要在 ExecuteTemplate 的第二個參數告訴模組要把哪個檔案作為主要渲染的模板。
err := tpl.ExecuteTemplate(os.Stdout, "index.html", data)
//如果是 ParseFile ,用 Execute 就可以了
//err := tpl.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
其中的這個 data 參數,就是要放入 template 的值,這裡以 string 為例:
var data []string = []string{"1", "2", "3", "Hello World"}
丟入方法函數到 template
要在 template 中使用自己設定的方法,需要建立一個 struct ,然後在 ParseFiles 類的操作之前,加入這個 struct。寫法:
var fc = template.FuncMap{
"conv": convetor, //加入自己的方法
}
func convetor(data string) string {
return fmt.Sprintln("give some value: ", data)
}
var tpl *template.Template
func init() {
//重點在於 Funcs 這個方法,參數是加入含有 FuncMap 結構的 struct,這麼一來就可以在模板中使用,且必須在 Parse 之前就加入 Func。
tpl = template.Must(template.New("").Funcs(fc).ParseGlob("./*.html"))
//單純用 ParseFiles 的方法
//tpl = template.Must(template.New("index.html").Funcs(fc).ParseFiles("index.html"))
}
於 Template 的操作,在下一節會提到。
Template 常用方法、變數使用
Template 可以自訂任何檔案,只要輸入檔案進去給 ParseFiles 或可以被 ParseGlob 讀取就可以了。. 點
在 Template 中,要顯示 Execute 的變數,要使用 {{ . }} ,這個點只會是一次性的,因為 Execute 的方法無法讀取多個變數,所以 {{ . }}} 將代表剛才寫的 data 。<p>{{.}}</p>
而如果傳入的 data 是一個 struct , 可能就會這樣寫:
<p>{{.FirstName}}</p>
自訂變數
Template 可以自訂變數,如果你覺得依靠 . 有點不好讀取,可以事先定義:<p>{{ $data := .}}, read data: {{ $data.FirstName }}</p>
迴圈
由於可能傳入的參數是 Slice 或是 map ,可以透過以下方法存取://讀取 slice (array)
{{ range . }} //. 也可以寫 $data
//這個 . 已經被換成迴圈的 . ,在這個區域內, . 不是 data 了,而是被迭代的內容。
<p>{{.}}</p>
{{end}}
//讀取 map 的方式
{{ range $key,$v := $data }}
<p>{{$key}} - {{ $v }}</p>
{{end}}
判斷 / 比較
在 Template 使用判斷,是使用以下方法:// if lt(小於) 第一個參數, 第二個, ....
{{if lt 1 2 }}
1 < 2
{{ end }}
// if eq(等於) 第一個參數,第二個, ...
{{ if eq 1 1}}
1 == 1
{{ end }}
// if gt(大於) 第一個參數,第二個, ...
{{ if gt 2 1 }}
2 > 1
{{ end }}
// if (布林)
{{ if true }}
{{ end }}
套用方法/函數
剛才在 if 中使用的 gt, eq, lt 其實就是 使用方法/函數的方式,在上一節所寫到的 conv 函式,在這裡的使用方法是:{{ conv . }}
//或
{{ conv "hello world" }}
//如果多個參數的情況下
{{ conv "1" "2"}}
pipeline 多重套用函數
如果使用多重的方法,可以這樣寫:{{ . | conv | toUpperCase | toLowerCase }}
分離式模板
要做到分離式模板, ParseFiles 和 ParseGlob 最好有不同的 html ,而且都要讀入,分離式模板的方法會在 Execute 就被執行,所以不用擔心 Execute 讀取不到要載入的分離式模板。widget.html:
//需要事先定義好 define
{{ define "splite" }}
<p>Hello world, this template is from splite.html, and this string is from {{.}}</p>
//{{ . }} 是接收來自呼叫者的參數
{{end}}
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo page</title>
</head>
<body>
//第一個參數是輸入 define 的名稱,然後丟入需要的參數
{{ template "splite" " =>index.html"}}
</body>
</html>
如此一來 Template 就會被組合在一起。
Reference:
https://golang.org/pkg/html/template/
https://golang.org/src/text/template/helper.go
https://astaxie.gitbooks.io/build-web-application-with-golang/en/07.4.html
沒有留言:
張貼留言