在前后端分离的时代,模板语言使用的已经很少了,不过很多特定的场景还是很有用的,这里介绍其基本使用方法。
简介
与大多数语言一样,使用 {{
和 }}
来做标识,其包裹的可以是表达式或者变量,如下是一个简单的示例。
package main
import (
"os"
"text/template"
)
type Friend struct {
Name string
}
type Person struct {
Name string
Emails []string
Friends []*Friend
}
func main() {
tpl := `Hello {{ .Name }}!
Emails:
{{- range .Emails }}
{{ . }}
{{- end }}
Friends:
{{- with .Friends -}}
{{ range . }}
{{ .Name -}}
{{ end }}
{{ end }}`
t := template.New("test")
t = template.Must(t.Parse(tpl))
p := &Person{
Name: "andy",
Emails: []string{"hello@example.com", "world@gexample.com"},
Friends: []*Friend{{
Name: "andy",
}, {
Name: "andy",
}},
}
t.Execute(os.Stdout, p)
}
渲染后输出如下内容。
Hello andy!
Emails:
hello@example.com
world@gexample.com
Friends:
andy
andy
也就是按照 New()
、Parse()
、Execute()
顺序分别创建、解析、渲染,其中 {{ . }}
就是 Execute()
中渲染的对象,可以以此引用其中的内容。
作用域
编写模板时会用到 .
点符号,例如 {{ . }}
、{{ len . }}
、{{ .Name }}
、{{ $x.Name }}
等,其代表当前作用域的当前对象。顶层就是 Execute()
函数的入参,如上述示例中的 {{ .Name }}
{{ .Emails }}
就相当于 p.Name
p.Emails
变量。
而对于 range
、with
、if
等内置关键字都有自己本地作用域,上述的 {{range .Emails}} ... {{end}}
中内部结构就是迭代时的每个元素,也就是 p.Emails
这个切片中的字符串。
变量
通过 {{ $var := value }}
声明变量,再用 {{ $var = value }}
重新赋值,通过 {{ $var }}
输出,或者通过 {{ $var := or value default }}
设置默认值。
Actions
在 {{
和 }}
中包裹的内容统称为 Action,分为数据求值和控制结构两种。
注释
通过 {{/* comments */}}
表示,而注释会占用一行,所以,通常会在前或者后加一个 -
符号去除空白字符。
去除空白
在替换的时候是完全按照文本进行的,除了需要评估和替换的地方,所有的分割符、空格、换行等都原样保留,为了模板可以方便查看一般会进行对齐,但实际内容可能不需要换行、空格之类,可以用如下方式去除。
在 {{
符号后加上短横线并保留一个或多个空格来去除前面的空白,包括换行符、制表符、空格等,例如 {{- xxx
;同理 xxx -}}
去除后面空白。
{{23}} < {{45}} -> 23 < 45
{{23}} < {{- 45}} -> 23 <45
{{23 -}} < {{45}} -> 23< 45
{{23 -}} < {{- 45}} -> 23<45
文本输出
输出很简单,直接使用 {{ pipeline }}
即可,其中 pipeline 代表的数据会产生与调用 fmt.Print()
类似的输出,例如整型的 3
会转换成字符串 "3"
输出。
条件语句
与编程语言类似,如下是常见的示例。
{{ if pipeline }} ... {{ end }}
{{ if pipeline }} ... {{ else }} ... {{ end }}
{{ if pipeline }} ... {{ else if pipeline }} ... {{ end }}
如果 pipeline
的值为空就不会输出,对应的空值有 false
、0
、nil
、""
等。
循环语句
// 简单循环
{{ range pipeline }} T1 {{ end }}
// 如果pipeline长度为0则输出else内容
{{ range pipeline }} T1 {{ else }} T0 {{ end }}
// 同时获取容器下标
{{ range $index, $value := pipeline }} T1 {{ end }}
循环的变量必须是可以迭代的类型值,例如数组、切片、字典、管道等。
模板使用
通过 {{ define "name" }} T {{ end }}
定义一个模板,再用 {{ template "name" }}
引用模板。
还有就是 {{ block "name" pipeline }} T1 {{ end }}
,增加了一层判断,如果存在名称为 name
的模板就引用,否则就执行自定义的内容。
Pipeline
和 Unix 中管道类似,用来连接多个命令,前面命令将计算结果传递给后个命令的最后位置,如下都输出 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"}}
with
如下的 with
会创建一个新的上下文环境,在此环境中的 .
与外面的 .
无关。
{{ with pipeline }} T1 {{ end }}
// 如果 pipeline 是空值则输出 T0
{{ with pipeline }} T1 {{ else }} T0 {{ end }}
{{ with arg }}
. // 此时 . 就是 arg
{{ end }}
函数
比较
包括了 eq
、ne
、lt
、le
、gt
、ge
等几个函数,使用方式类似 {{ if (ge .Usage .Limit) }}
这种方式。
index
返回 index 后面的第一个参数的某个索引对应的元素值,例如 {{index x 1}}
表示 x[1]
,其中 x
必须是一个 map
、slice
、array
。
参考
- fasttemplate 一个更加简单高效的渲染库实现。