模板template
模板基础
html/template
包实现了数据驱动的模板,用于生成可防止代码注入的安全的HTML内容。它提供了和text/template
包相同的接口,Go语言中输出HTML的场景都应使用html/template
这个包。
- 模板文件通常定义为
.tmpl
和.tpl
为后缀(也可以使用其他的后缀),必须使用UTF8
编码。
- 模板文件中使用
{{`和`}}
包裹和标识需要传入的数据。
- 传给模板这样的数据就可以通过点号(
.
)来访问,如果数据是复杂类型的数据,可以通过{ { .FieldName }}来访问它的字段。
- 除
{{`和`}}
包裹的内容外,其他内容均不做修改原样输出。
模板使用三部曲
定义模板
解析模板
1
| func ParseFiles(filenames ...string) (*Template, error)
|
渲染模板
1
| func (t *Template) Execute(wr io.Writer, data interface{}) error
|
一个小栗子
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| package main
import ( "fmt" "html/template" "net/http" )
type User struct { Name string Gender string Age int }
func sayHello(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles("./hello.tmpl") if err != nil { fmt.Println("create template failed, err:", err) return }
u1 := User{ Name: "梅西", Gender: "男", Age: 36, }
mp := make(map[string]interface{}) mp["name"] = "c罗" mp["gender"] = "男" mp["age"] = 21
arr := []string{ "足球", "篮球", "羽毛球", }
err = tmpl.Execute(w, map[string]interface{}{ "u1": u1, "mp": mp, "arr": arr, })
if err != nil { fmt.Println("传递参数出错,err:", err) return }
}
func main() { http.HandleFunc("/", sayHello) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("HTTP server failed, err:", err) return } }
|
hello.tmpl文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Hello</title> </head> <body> <p>hello</p> <p>{{ .u1.Name }}</p> <p>{{ .u1.Gender }}</p> <p>{{ .u1.Age }}</p> <hr>
<p>hello</p> <p> {{ .mp.name }} </p> <p> {{ .mp.gender }} </p> <p> {{ .mp.age }} </p> <hr>
{{ range $idx,$hobby := .arr }} <p>{{$idx}} - {{$hobby}}</p> {{ end }} </body> </html>
|
基础模板语法
注释:
pipeline:管道|
变量:$obj := {{.}}
移除空格:{{- .Name -}}
条件判断:
1 2 3 4
| {{if ...}} {{else if ...}} {{else}} {{end}}
|
range:
比较函数:
1 2 3 4 5 6 7 8
| eq 如果arg1 == arg2则返回真 ne 如果arg1 != arg2则返回真 lt 如果arg1 < arg2则返回真 le 如果arg1 <= arg2则返回真 gt 如果arg1 > arg2则返回真 ge 如果arg1 >= arg2则返回真
{{eq arg1 arg2}}
|
模板嵌套
自定义函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package main
import ( "fmt" "html/template" "io/ioutil" "net/http" )
type User struct { Name string Gender string Age int }
func f(w http.ResponseWriter, r *http.Request) { fByte, err := ioutil.ReadFile("./f.tmpl") if err != nil { fmt.Println("read html failed, err:", err) return }
fun1 := func(arg string) (string, error) { return arg + "是球王", nil } tmpl, err := template.New("f"). Funcs(template.FuncMap{"fun1": fun1}). Parse(string(fByte)) if err != nil { fmt.Println("create template failed, err:", err) return }
user := User{ Name: "梅西", Gender: "男", Age: 35, }
tmpl.Execute(w, user) }
func main() { http.HandleFunc("/", f) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("failed err:", err) return } }
|
嵌套模板
我们可以在template中嵌套其他的template。这个template可以是单独的文件,也可以是通过define
定义的template。
f.tmpl
文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>tmpl test</title> </head> <body> <h1>测试嵌套template语法</h1> <hr> {{template "ul.tmpl"}} <hr> {{template "ol.tmpl"}} </body> </html>
{{ define "ol.tmpl"}} <ol> <li>吃饭</li> <li>睡觉</li> <li>打豆豆</li> </ol> {{end}}
|
ul.tmpl
文件内容如下:
1 2 3 4 5
| <ul> <li>注释</li> <li>日志</li> <li>测试</li> </ul>
|
main.go文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package main
import ( "fmt" "html/template" "net/http" )
type User struct { Name string Gender string Age int }
func fun1(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles("./f.tmpl", "./ul.tmpl")
if err != nil { fmt.Println("create failed, err :", err) return } user := User{ Name: "梅西", Gender: "男", Age: 36, } tmpl.Execute(w, user) }
func main() { http.HandleFunc("/tmpl", fun1) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("Http server failed, err:", err); return } }
|
模板继承
block: block
是定义模板{{define "name"}} T1 {{end}}
和执行{{template "name" pipeline}}
缩写,典型的用法是定义一组根模板,然后通过在其中重新定义块模板进行自定义。
定义根模板base.tmpl
1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE html> <html lang="zh-CN"> <head> <title>Go Templates</title> </head> <body> <h1>模板继承</h1> <div class="container-fluid"> {{block "content" . }}{{end}} </div> </body> </html>
|
定义一个home.tmpl
继承base.tmpl
1 2 3 4 5
| {{template "base.tmpl"}}
{{define "content"}} <div>Hello world!</div> {{end}}
|
解析模板和渲染模板
1 2 3 4 5 6 7 8 9 10 11 12
| func home(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseGlob("templates/*.tmpl") if err != nil { fmt.Println("create failed err:", err) return } err = tmpl.ExecuteTemplate(w, "home.tmpl", nil) if err != nil { fmt.Println("render template failed, err:", err) return } }
|