在MVC(model-view-controller)架構中,我們經常會用到模板文件,本片博文介紹html/template的使用方法,關於模板語法,請參考我的另一篇博客Go語言中的html/template標準庫學習筆記一(template語法介紹)
1.先介紹一下Template結構體
// Template is a specialized Template from "text/template" that produces a safe
// HTML document fragment.
type Template struct {
// Sticky error if escaping fails, or escapeOK if succeeded.
escapeErr error
// We could embed the text/template field, but it's safer not to because
// we need to keep our version of the name space and the underlying
// template's in sync.
text *template.Template
// The underlying template's parse tree, updated to be HTML-safe.
Tree *parse.Tree
*nameSpace // common to all associated templates
}
在Template中text爲*template.Template
類型,保存了模板的基礎信息:
// Template is the representation of a parsed template. The *parse.Tree
// field is exported only for use by html/template and should be treated
// as unexported by all other clients.
type Template struct {
name string
*parse.Tree
*common
leftDelim string
rightDelim string
}
2.新建模板
我們可以使用func New(name string) *Template
新建一個模板,並指定模板的名稱。
package main
import (
"fmt"
"html/template"
)
func main() {
// 這裏我們創建了一個名稱爲test的模板
tpl := template.New("test")
// 查看模板名稱
fmt.Println(tpl.Name())
}
Output:
$ go run main.go
test
3. 查看模板名稱
因爲name字段我們是不能直接查看的,因此我們需要使用func (t *Template) Name() string
方法獲取模板名稱。
4.解析模板
(1)使用func ParseFiles(filenames ...string) (*Template, error)
解析模板文件
我們在項目的templates目錄添加一個index.html文件,文件內容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>html/template教程</title>
</head>
<body>
{{ . }}
</body>
</html>
文件中的{{ . }}表示接收到的內容,然後我們解析index.html模板:
package main
import (
"html/template"
"os"
)
func main() {
tpl, err := template.ParseFiles("templates/index.html")
if err != nil {
panic(err)
}
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.Execute(os.Stdout, "hello world"); err != nil {
panic(err)
}
}
Output:
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>html/template教程</title>
</head>
<body>
hello world
</body>
</html>
我們可以看到已經成功解析到了index.html模板,並且進行了渲染。
(2)使用func (t *Template) Parse(text string) (*Template, error)
解析字符串
package main
import (
"html/template"
"os"
)
func main() {
// 在Parse方法中傳入要解析的字符串`Output: {{ . }}`
tpl, err := template.New("test").Parse(`Output: {{ . }}`)
if err != nil {
panic(err)
}
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.Execute(os.Stdout, "hello world"); err != nil {
panic(err)
}
}
Output:
$ go run main.go
Output: hello world
5.模板渲染
(1)使用func (t *Template) Execute(wr io.Writer, data interface{}) error
渲染模板,這個在前面已經用到了,就不舉例了。
(2)使用func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error
渲染指定模板
package main
import (
"html/template"
"os"
)
func main() {
// 在Parse方法中傳入要解析的字符串`Output: {{ . }}`
tpl, err := template.New("test").Parse(`Output: {{ . }}`)
if err != nil {
panic(err)
}
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.ExecuteTemplate(os.Stdout, "test", "hello world"); err != nil {
panic(err)
}
}
Output:
$ go run main.go
Output: hello world
(3)`func ParseGlob(pattern string) (*Template, error)
`ParseGlob函數從指定的匹配文件中創建並解析模板,必須得至少匹配一個文件.
這裏我們在templates目錄創建兩個文件:
body.html文件內容爲:
{{ define "body" }}
<body>
<p>Hello World</p>
</body>
{{ end }}
header.html文件內容爲:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>html/template教程</title>
</head>
{{ template "body" . }}
</html>
我們使用ParseGlob進行模板解析:
package main
import (
"html/template"
"os"
)
func main() {
tpl, err := template.ParseGlob("templates/*.html")
if err != nil {
panic(err)
}
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.ExecuteTemplate(os.Stdout, "header.html", nil); err != nil {
panic(err)
}
}
Output:
$ go run main.go
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>html/template教程</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
6.添加模板函數
模板文件中支持函數操作,我們可以使用func (t *Template) Funcs(funcMap FuncMap) *Template
方法給模板添加函數,模板函數的返回值最多爲兩個,並且如果有第二個參數,則必須爲error類型。
package main
import (
"html/template"
"os"
"strings"
)
// 定義模板函數返回hello world
func Hello() (string, error) {
return "hello world", nil
}
func main() {
// 首先創建一個函數字典用於註冊函數
funcMap := template.FuncMap{
"hello": Hello,
}
tpl, err := template.New("test").Funcs(funcMap).Parse(`Output: {{ hello }}`)
if err != nil {
panic(err)
}
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.Execute(os.Stdout, "hello world"); err != nil {
panic(err)
}
}
Output:
$ go run main.go
Output: hello world
7. 其他方法
(1)func Must(t *Template, err error) *Template
Must函數會在Parse返回err不爲nil時,調用panic,不需要初始化後再調用Parse方法去檢測,下面舉個例子:
package main
import (
"html/template"
"os"
)
func main() {
// Must會判斷解析結果是否報錯,如果報錯則panic
// {{ templates/*.html是錯誤的模板語法,因此會報錯
tpl := template.Must(template.New("test").Parse("{{ templates/*.html"))
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.ExecuteTemplate(os.Stdout, "test", nil); err != nil {
panic(err)
}
}
Output:
$ go run main.go
panic: template: test:1: unexpected bad character U+002F '/' in command
goroutine 1 [running]:
html/template.Must(...)
c:/Go/src/html/template/template.go:372
main.main()
D:/GOCODE/Test/main.go:15 +0xff
exit status 2
(2)func (t *Template) Delims(left, right string) *Template
Delims可以自定義模板中的分界符號,默認是{{}}
package main
import (
"html/template"
"os"
)
func main() {
// ## Delims()方法用來指定分隔符來分割字符串,隨後會使用Parse, ParseFiles, or ParseGlob方法進行模板內容解析
tpl := template.Must(template.New("test").Delims("{{", "]]").Parse("{{ . ]]"))
// 如果不報錯則將內容輸出,os.Stdout爲標準輸出
if err := tpl.Execute(os.Stdout, "hello world"); err != nil {
panic(err)
}
}
Output:
$ go run main.go
hello world
可以看到界定符被改成{{]]
,程序正確對模塊進行了解析。