模板引擎
大约 8 分钟
模板引擎
html/template
包提供了数据驱动的模板,用于生成可以对抗代码注入的HTML安全输出。一般在传统的MVC架构中,前后端不分离的情况下,为了实现动态网页的效果,模板引擎是必不可少的。Java
中著名的有freemaker
themyleaf
,在go
语言中,标准库的模板包就足够基本使用了。
作用域
先看一个示例
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web</title>
</head>
<body>
{{ . }}
</body>
</html>
.
表示的是当前作用域对象,如果传入的是字符串,那么就是字符串,如果是对象,还可以通过.field
来访问。
解析
func main() {
tempFile, err := template.ParseFiles("test.html")
if err != nil {
fmt.Println(err)
return
}
tempFile.Execute(os.Stdout,"hello")
}
去除空白
template在解析时,会保留每一个字符,倘若想要去除一些空白字符时,可以使用-
来进行对应的操作。
例如
{{30 -}} > {{15}}
会去除掉}} >
之间的空格,最终效果是30> 15
,下方的例子同理
{{30 -}} > {{- 15}}
得到30>15
管道
其类似于unix
系统的管道运算符,是产生数据的操作,即pipeline
,并不是只有|
才是pipeline,只要能产生数据的操作都是pipeline
{{.}} | printf "%s"
再例如,括号中的操作也是pipeline
{{println (len "hello world")}}
变量
模板中可以定义变量,语法如下
$val := pipeline
例子
{{$length := (len "hello")}}
{{println $length }}
需要注意的地方:
- 变量的作用域,只要出现
end
,当前层次的作用域结束,内层变量可以访问外层,但是外层不能访问内层。 - 全局变量
$
是模板的最顶级作用域对象,且一直不会有变化。 - 变量不可以在模板之间继承
条件判断
语法如下,理解起来比较简单
{{if pipeline}} condition1 {{end}}
{{if pipeline}} condition1 {{else}} condition2 {{end}}
{{if pipeline}} condition1 {{else if pipeline2}} condition2 {{else}} condition3 {{end}}
迭代
可以适用于切片,map,数组,或者channel
语法
{{range pipeline}} 1 {{end}} //为0值时直接跳过
{{range pipeline}} 1 {{else}} 2 {{end}} //为0值时执行else
也可以迭代赋值,就像写go循环一样
{{range $val := pipeline}}
{{range $key,$val := pipeline}}
With
with end
用于设置当前作用域对象的值,即.
{{with pipeline}} 1 {{end}} //为0值是跳过
{{with pipeline}} 1 {{else}} 2 {{end}} //为0值时执行else
函数
以下是内置函数
and
函数返回它的第一个empty参数或者最后一个参数;
就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
返回第一个非empty参数或者最后一个参数;
亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
返回它的单个参数的布尔值的否定
len
返回它的参数的整数类型长度
index
执行结果为第一个参数以剩下的参数为索引/键指向的值;
如"index x 1 2 3"返回x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
print
即fmt.Sprint
printf
即fmt.Sprintf
println
即fmt.Sprintln
html
返回其参数文本表示的HTML逸码等价表示。
urlquery
返回其参数文本表示的可嵌入URL查询的逸码等价表示。
js
返回其参数文本表示的JavaScript逸码等价表示。
call
执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
其中Y是函数类型的字段或者字典的值,或者其他类似情况;
call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
该函数类型值必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;
eq 如果arg1 == arg2则返回真
ne 如果arg1 != arg2则返回真
lt 如果arg1 < arg2则返回真
le 如果arg1 <= arg2则返回真
gt 如果arg1 > arg2则返回真
ge 如果arg1 >= arg2则返回真
也可以自定义函数在模板中使用
myFunc := func(arg string) (string, error) {
return "hello", nil
}
//在Parse之前调用Funcs添加自定义的myFunc函数
tmpl, err := template.New("hello").Funcs(template.FuncMap{"myFunc": myFunc}).Parse(string(htmlByte))
{{myFunc "world"}}
嵌套Template
可以在Template中嵌套Template,可以是文件,也可以是define定义的Template
test.txt
This is a test
main.txt
{{template test.txt}}
{{template virtual.txt}}
This is main
{{define "virtual.txt"}}
This a define template
解析main.txt
文件效果如下
This is a test
This a define template
This is main