入门示例
package main
import (
"html/template"
"net/http"
)
func tmpl(w http.ResponseWriter, r *http.Request) {
t1, err := template.ParseFiles("test.html")
if err != nil {
panic(err)
}
t1.Execute(w, "hello world")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/tmpl", tmpl)
server.ListenAndServe()
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web</title>
</head>
<body>
{{ . }}
</body>
</html>
上面的 {{ . }}
会被替换为 hello world
点和作用域
type Person struct {
Name string
Age int
}
func main(){
p := Person{"longshuai",23}
tmpl, _ := template.New("test").Parse("Name: {{.Name}}, Age: {{.Age}}")
_ = tmpl.Execute(os.Stdout, p)
}
去除空白
{{23}} < {{45}} -> 23 < 45
{{23}} < {{- 45}} -> 23 <45
{{23 -}} < {{45}} -> 23< 45
{{23 -}} < {{- 45}} -> 23<45
注释
注释方式:{{/* a comment */}}
注释后的内容不会被引擎进行替换, 但仍会占用一行。所以应该去除前缀或后缀空白。
{{- /* a comment without prefix/suffix space */}}
{{/* a comment without prefix/suffix space */ -}}
{{- /* a comment without prefix/suffix space */ -}}
注: 应该只去除前缀或后缀空白,不要同时都去除,否则会破坏原有的格式
t.Parse(
`hello {{.UserName}}!
{{- /* this line is a comment */}}
{{ range .Emails }}
an email {{ . }}
{{- end }}
管道
{{println (len "output")}}
{{`"output"`}}
{{printf "%q" "output"}}
{{"output" | printf "%q"}}
{{printf "%q" (print "out" "put")}}
{{"put" | printf "%s%s" "out" | printf "%q"}}
{{"output" | printf "%s" | printf "%q"}}
变量
{{- $how_long :=(len "output")}}
{{- println $how_long}} // 输出6
tx := template.Must(template.New("hh").Parse(
`{{range $x := . -}}
{{$y := 333}}
{{- if (gt $x 33)}}{{println $x $y ($z := 444)}}{{- end}}
{{- end}}
`))
s := []int{11, 22, 33, 44, 55}
_ = tx.Execute(os.Stdout, s)
// 输出结果:
44 333 444
55 333 444
结构体方法
{{.Variable.Method arg1 arg2 ...}}
: .Variable 表示一个变量,Method表示该变量的一个方法,arg1、arg2等表示方法的参数{{.Person.GetName}}
: 调用 Person 变量的 GetName 方法,并输出该方法的返回值。
https://juejin.cn/post/7268050036473249811
条件判断
{{if pipeline}} T1 {{end}}
{{if pipeline}} T1 {{else}} T0 {{end}}
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
其中第三和第四是等价的。
pipeline为false的情况是各种数据对象的0值
:数值0,指针或接口是nil,数组、slice、map或string则是len为0。
range ... end
tx := template.Must(template.New("hh").Parse(
`{{range $x := . -}}
{{println $x}}
{{- end}}
`))
s := []int{11, 22, 33, 44, 55}
_ = tx.Execute(os.Stdout, s)
{{range $value := .}}
{{range $key,$value := .}}
如果range中只赋值给一个变量,则这个变量是当前正在迭代元素的值。如果赋值给两个变量,则第一个变量是索引值(map/slice是数值,map是key),第二个变量是当前正在迭代元素的值。
with ... end
with ... end
用来设置 "."
的值
{{with pipeline}} T1 {{end}}
{{with pipeline}} T1 {{else}} T0 {{end}}
对于第一种格式,当pipeline不为0值的时候,点"."设置为pipeline运算的值,否则跳过。对于第二种格式,当pipeline为0值时,执行else语句块,否则"."设置为pipeline运算的值,并执行T1。
内置函数和自定义函数
- and 返回第一个为空的参数或最后一个参数。可以有任意多个参数。
- not 布尔取反。只能一个参数。
- or 返回第一个不为空的参数或最后一个参数。可以有任意多个参数。
- print, printf, println 分别等价于fmt包中的Sprint、Sprintf、Sprintln
- index 对可索引对象进行索引取值。第一个参数是索引对象,后面的参数是索引位。例:
index x 1 2 3
- call 显式调用函数。第一个参数必须是函数类型,且不是内置函数. 例:
call .GetSum 1 2
- eq arg1 arg2: arg1 == arg2时为true
- ne arg1 arg2:arg1 != arg2时为true
- lt arg1 arg2:arg1 < arg2时为true
- le arg1 arg2:arg1 <= arg2时为true
- gt arg1 arg2:arg1 > arg2时为true
- ge arg1 arg2:arg1 >= arg2时为true
对于eq函数,支持多个参数:eq arg1 arg2 arg3 arg4...
-> arg1==arg2 || arg1==arg3 || arg1==arg4
嵌套template: define和template
func main() {
t1 := template.New("test1")
tmpl, _ := t1.Parse(
`{{- define "T1"}}ONE {{println .}}{{end}}
{{- define "T2"}}TWO {{println .}}{{end}}
{{- define "T3"}}{{template "T1"}}{{template "T2" "haha"}}{{end}}
{{- template "T3" -}}
`)
_ = tmpl.Execute(os.Stdout, "hello world")
}
// 输出结果
ONE <nil>
TWO haha
模板之间的变量是不会继承的
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("t1.html", "t2.html")
t.Execute(w, "Hello World!")
}
t1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=9">
<title>Go Web Programming</title>
</head>
<body>
<div> This is t1.html before</div>
<div>This is the value of the dot in t1.html - [{{ . }}]</div>
<hr />
{{ template "t2.html" }}
<hr />
<div> This is t1.html after</div>
</body>
</html>
t2.html
<div style="background-color: yellow;">
This is t2.html<br/>
This is the value of the dot in t2.html - [{{ . }}]
</div>
等价于:
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("t1.html")
t.Execute(w, "Hello World!")
}
t1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=9">
<title>Go Web Programming</title>
</head>
<body>
<div> This is t1.html before</div>
<div>This is the value of the dot in t1.html - [{{ . }}]</div>
<hr />
{{ template "t2.html" }}
<hr />
<div> This is t1.html after</div>
</body>
</html>
{{define "t2.html"}}
<div style="background-color: yellow;">
This is t2.html<br/>
This is the value of the dot in t2.html - [{{ . }}]
</div>
{{end}}
block块
func process(w http.ResponseWriter, r *http.Request) {
rand.Seed(time.Now().Unix())
t := template.New("test")
if rand.Intn(10) > 5 {
t, _ = template.ParseFiles("home.html", "red.html")
} else {
t, _ = template.ParseFiles("home.html")
}
t.Execute(w,"")
}
red.html
:
{{ define "content" }}
<h1 style="color: red;">Hello World!</h1>
{{ end }}
blue.html
:
{{ define "content" }}
<h1 style="color: blue;">Hello World!</h1>
{{ end }}
home.html
:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
{{ block "content" . }}
<h1 style="color: blue;">Hello World!</h1>
{{ end }}
</body>
</html>
当执行else语句块的时候,发现home.html中要执行名为content的模板,但在ParseFiles()中并没有解析包含content模板的文件。于是执行block定义的content模板。而执行非else语句的时候,因为red.html中定义了content,会直接执行red.html中的content。
block通常设置在顶级的根文件中,例如上面的home.html中。
Go template用法详解 https://www.cnblogs.com/f-ck-need-u/p/10053124.html
深入剖析Go template https://www.cnblogs.com/f-ck-need-u/p/10035768.html
https://cloud.tencent.com/developer/article/1683688